Мы переносим приложение из IBM WebSphere Traditiona 8.5 в OpenLiberty 19.0.0.12 (оба с IBM JDK 8).
В процессе, в котором мы хотим избавиться от транзакций XA, есть только один метод который на самом деле использует два разных источника данных, но только для записи во второй источник данных (первый используется только для чтения).
Итак, представьте что-то вроде этого:
@Path("/path_to_my_service")
@Stateless
public class MyService extends ByBaseService {
private static final long serialVersionUID = 3470660101451196317L;
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response create(Model model) {
try ( Connection connectionFromDataSourceOne = ...;
Connection connectionFromDataSourceTwo = ... ) {
// performs some reading from connectionFromDataSourceOne
// try to performe writing on connectionFromDataSourceTwo
) catch () {
...
} finally {
...
}
}
}
Имейте в виду, что существуют различные операции чтения (от ds1) и записи (до ds2), но они смешаны сложным способом, поэтому для разделения транзакции потребуется глубокий рефакторинг, которого мы сейчас избегаем.
Но мы получаем эту ошибку:
J2CA0030E: Перехват метода пойман java .lang.IllegalStateException: незаконная попытка зачисления нескольких 1P C XAResources
Есть ли способ, чтобы менеджер транзакций 2P C не требовался без какого-либо серьезного рефакторинга кода?
Заранее спасибо.
Редактировать после решения Ион был найден (2020-01-11):
Мы создали перед небольшим ПО C то, что нам нужно, а затем мы попытались найти решение просто изменить управление транзакциями:
@TransactionManagement(TransactionManagementType.BEAN)
Тогда нам удалось применить его к реальному сценарию, и, похоже, все работает правильно. Мы публикуем ПО C на случай, если кому-то будет полезно для тестирования:
@Stateless
@Path("/test/transaction")
@TransactionManagement(TransactionManagementType.BEAN)
public class TransactionTestRest implements Serializable {
private static final long serialVersionUID = -2963030487875284408L;
private static final Logger logger = LoggerFactory.getLogger( TransactionTestRest.class );
@Resource(lookup = DataConsts.DS1_JNDI, name = DataConsts.DS1_NAME )
private DataSource ds1;
@Resource(lookup = DataConsts.DS2_JNDI, name = DataConsts.DS2_NAME )
private DataSource ds2;
private Properties baseProperties() {
Properties props = new Properties();
props.setProperty( "testVersion" , "3" );
return props;
}
@GET
@Path("/conntest_all")
@Produces(MediaType.APPLICATION_JSON)
public Response testAll() {
Response res = null;
try ( Connection conn1 = this.ds1.getConnection();
Connection conn2 = this.ds2.getConnection() ) {
Properties props = this.baseProperties();
props.setProperty( "testConn1" , conn1.getMetaData().getUserName() );
props.setProperty( "testConn2" , conn2.getMetaData().getUserName() );
conn2.setAutoCommit( false );
try ( Statement stm1 = conn1.createStatement();
ResultSet rs1 = stm1.executeQuery( "SELECT * FROM test_ds1" );
PreparedStatement pstm2 = conn2.prepareStatement( "INSERT INTO test_ds2 ( ID ) VALUES ( ? )" ) ) {
while ( rs1.next() ) {
BigDecimal id = rs1.getBigDecimal( "ID" );
pstm2.setBigDecimal( 1 , id );
pstm2.executeUpdate();
}
conn2.commit();
props.setProperty( "result" , "OK!");
} catch (Exception ie) {
props.setProperty( "result" , "Error:"+ie );
conn2.rollback();
} finally {
conn2.setAutoCommit( true );
}
res = Response.ok( props ).build();
} catch (Exception e) {
logger.error( "Error on conntest_all "+e, e );
res = Response.status( Response.Status.INTERNAL_SERVER_ERROR ).build();
}
return res;
}
@GET
@Path("/conntest_1")
@Produces(MediaType.APPLICATION_JSON)
public Response test1() {
Response res = null;
try ( Connection conn1 = this.ds1.getConnection();) {
Properties props = this.baseProperties();
props.setProperty( "testConn1" , conn1.getMetaData().getUserName() );
res = Response.ok( props ).build();
} catch (Exception e) {
logger.error( "Error on conntest_1 "+e, e );
res = Response.status( Response.Status.INTERNAL_SERVER_ERROR ).build();
}
return res;
}
@GET
@Path("/conntest_2")
@Produces(MediaType.APPLICATION_JSON)
public Response test2() {
Response res = null;
try ( Connection conn2 = this.ds2.getConnection();) {
Properties props = this.baseProperties();
props.setProperty( "testConn2" , conn2.getMetaData().getUserName() );
res = Response.ok( props ).build();
} catch (Exception e) {
logger.error( "Error on conntest_2 "+e, e );
res = Response.status( Response.Status.INTERNAL_SERVER_ERROR ).build();
}
return res;
}
}