我试图使用JBossTs独立设置JTA,因为需要更新两个数据源。但是,Transaction的基本功能不起作用。
简单来说,如果我的DAO尝试插入两个记录,而第二个记录失败,则第一个记录仍将提交到数据库中。
我的DAO:
narayana-jta:4.17.43。最终版 org.springframework:5.1.7.RELEASE 休眠核心: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");
}
}
日志:
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
似乎DAO执行的每个SQL语句都在单独的事务中而不是整个方法中。此外,是否调用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>
休眠配置
<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
无效,因为没有任何内容提交到数据库中。没有看到任何错误。如果再次执行该方法,则会抛出异常,表明违反了唯一约束,但DB中的表为空。看来,JTA事务的提交或回滚似乎没有任何影响。
更新2:通过上述更改,正在执行SQL,但未提交任何内容。如果再次执行该代码,则会收到SQL唯一约束异常,但DB中的表为空。