JTA事务不会被提交或回滚-JBossTS,Arjuna

时间:2019-06-20 06:58:38

标签: java spring hibernate jta jbossts

我试图使用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中的表为空。

0 个答案:

没有答案