Я пытаюсь настроить JTA автономно, используя JBossTs, так как необходимо обновить два источника данных.Однако базовая функциональность транзакции не работает.
Проще говоря, если мой DAO пытается вставить две записи, а вторая не удается, первая по-прежнему фиксируется в базе данных.
Мой DAO:
Нараяна-JTA: 4.17.43.Final org.springframework: 5.1.7.RELEASE hibernate-core: 5.3.10 .Final
public void insertRow2(String name, String model) {
try {
getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
// the table has a primary key on columns MODEL and NAME
// First call to the method works and this hard-coded row
// is inserted.
// CASE1: In the second call, rec1 saveOrUpdate throws exception and nothing is
// inserted.
// CASE2: If the inputs in the method violate the PRIMARY KEY ON table,
// and rec1 does not, rec1 still gets inserted, instead of the entire
// transaction getting rolled back
TestJTARecord rec1 = new TestJTARecord();
rec1.setModel("model1");
rec1.setName("name1");
session.saveOrUpdate(rec1);
TestJTARecord rec = new TestJTARecord();
rec.setModel(model);
rec.setName(name);
session.saveOrUpdate(rec);
session.flush();
return rec.getModelId();
}
});
}catch (Exception e) {
throw new RuntimeException("INSERTROW2");
}
}
LOG:
2019-06-20 12:50:54,783 DEBUG org.springframework.transaction.jta.JtaTransactionManager Creating new transaction with name [xxxServiceImpl.save]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-java.lang.Exception [getTransaction:372 {}]
2019-06-20 12:50:54,783 DEBUG org.hibernate.SQL select hibernate_sequence.nextval from dual [logStatement:94 {}]
2019-06-20 12:50:54,805 DEBUG org.hibernate.SQL select hibernate_sequence.nextval from dual [logStatement:94 {}]
2019-06-20 12:50:54,807 DEBUG org.hibernate.SQL insert into TESTJTA (model, name, modelid) values (?, ?, ?) [logStatement:94 {}]
2019-06-20 12:50:54,812 TRACE org.hibernate.type.descriptor.sql.BasicBinder binding parameter [1] as [VARCHAR] - [model1] [bind:65 {}]
2019-06-20 12:50:54,813 TRACE org.hibernate.type.descriptor.sql.BasicBinder binding parameter [2] as [VARCHAR] - [name1] [bind:65 {}]
2019-06-20 12:50:54,813 TRACE org.hibernate.type.descriptor.sql.BasicBinder binding parameter [3] as [INTEGER] - [14501] [bind:65 {}]
2019-06-20 12:50:54,820 DEBUG org.hibernate.SQL insert into TESTJTA (model, name, modelid) values (?, ?, ?) [logStatement:94 {}]
2019-06-20 12:50:54,821 TRACE org.hibernate.type.descriptor.sql.BasicBinder binding parameter [1] as [VARCHAR] - [test2] [bind:65 {}]
2019-06-20 12:50:54,821 TRACE org.hibernate.type.descriptor.sql.BasicBinder binding parameter [2] as [VARCHAR] - [test1] [bind:65 {}]
2019-06-20 12:50:54,821 TRACE org.hibernate.type.descriptor.sql.BasicBinder binding parameter [3] as [INTEGER] - [14502] [bind:65 {}]
2019-06-20 12:50:54,822 ERROR xxxServiceImpl ========> EXCEPTION CAUGHT [error:240 {}]
java.lang.RuntimeException: INSERTROW2
at xxxDAOImpl.insertRow2(xxxDAOImpl.java:199) ~[xxx.jar:?]
at xxxServiceImpl.save(xxxServiceImpl.java:84) ~[xxx.jar:?]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_66]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_66]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_66]
at java.lang.reflect.Method.invoke(Method.java:497) ~[?:1.8.0_66]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:295) [spring-tx-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) [spring-tx-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) [spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) [spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at com.sun.proxy.$Proxy71.save(Unknown Source) [?:?]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_66]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_66]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_66]
at java.lang.reflect.Method.invoke(Method.java:497) ~[?:1.8.0_66]
2019-06-20 12:50:54,823 DEBUG org.springframework.transaction.jta.JtaTransactionManager Initiating transaction rollback [processRollback:836 {}]
Caused by: java.lang.RuntimeException: INSERTROW2
at xxxDAOImpl.insertRow2(xxxDAOImpl.java:199) ~[xxx.jar:?]
at xxxServiceImpl.save(xxxServiceImpl.java:84) ~[xxx.jar:?]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_66]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_66]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_66]
at java.lang.reflect.Method.invoke(Method.java:497) ~[?:1.8.0_66]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:295) ~[spring-tx-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) ~[spring-tx-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at com.sun.proxy.$Proxy71.save(Unknown Source) ~[?:?]
... 9 more
Кажется, что каждый SQL-оператор, выполняемый DAO, находится в отдельной транзакции вместо всего метода.Кроме того, вызов flush () или нет не оказывает никакого влияния.
Тот же код работает, как и ожидалось, если я использую HibernateTransactionManager.
<bean class="com.arjuna.ats.jta.TransactionManager" factory-method="transactionManager" id="arjunaTransactionManager" />
<bean class="com.arjuna.ats.jta.UserTransaction" factory-method="userTransaction" id="arjunaUserTransaction" />
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="arjunaTransactionManager" />
<property name="userTransaction" ref="arjunaUserTransaction" />
</bean>
Источник даты
<bean id="testJTA" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>com.arjuna.ats.jdbc.TransactionalDriver</value>
</property>
<property name="url" value="${database.url}"/>
<property name="username">
<value>testjta</value>
</property>
<property name="password">
<value>testjta</value>
</property>
</bean>
Hibernate Config
<bean id="testJTASessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<description>
Hibernate session support bean. Additional mappings go into mappingResources list.
</description>
<property name="dataSource" ref="testJTA"/>
<property name="jtaTransactionManager" ref="transactionManager"/>
<property name="mappingResources">
<list>
<value>hibernate/TestJTA.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${database.hibernate.dialect}</prop>
<!-- <prop key="hibernate.connection.isolation">3</prop> -->
<prop key="hibernate.connection.autocommit">false</prop>
<!-- <prop key="hibernate.flushMode">COMMIT</prop> -->
<prop key="hibernate.transaction.coordinator_class">jta</prop>
<prop key="hibernate.current_session_context_class">jta</prop>
<prop key="hibernate.transaction.jta.platform">org.hibernate.service.jta.platform.internal.JBossStandAloneJtaPlatform</prop>
<prop key="hibernate.jta.allowTransactionAccess">true</prop>
</props>
</property>
</bean>
Обновление 1: использование org.apache.tomcat.jdbc.pool.XADataSource
и установка defaultAutoCommit=false
не работают, поскольку в базе данных ничего не фиксируется.Не вижу ошибок.Если я выполню метод еще раз, будет сгенерировано исключение, говорящее о нарушении уникального ограничения, но таблица в БД пуста.Кажется, что принятие или откат транзакции JTA, кажется, не имеет никакого влияния.
Обновление 2: с изменением выше, SQL выполняется, но ничего не фиксируется.Если я выполню код снова, я получу исключение уникального ограничения SQL, но таблица в БД пуста.