Java Spring JTA事务回滚失败
我需要帮助来解释为什么尽管在日志中看到回滚消息,但我的JTA事务仍未能真正回滚。 我的安装程序有一个MySQL数据库和一个Microsoft SQLserver数据库。我为两个数据库的事务数据源创建了2个JNDI(tomcat-7)资源(请参阅我的META-INF/context.xml) 我调用了com.my.AService.create(obj)。它是一种将引发异常以测试回滚是否有效的方法。在测试结束时,我可以在日志中看到一条回滚消息。但是当我检查数据库时,我看到了应该回滚的提交记录。(请参阅我的截断日志) 为什么回滚不起作用?我怎么修理它 我正在使用: ApacheTomcat 7.0.50 jtom Spring框架3.2.3版本 Trucated日志,其中我看到空指针异常的回滚消息:Java Spring JTA事务回滚失败,java,spring,jdbc,transactions,jta,Java,Spring,Jdbc,Transactions,Jta,我需要帮助来解释为什么尽管在日志中看到回滚消息,但我的JTA事务仍未能真正回滚。 我的安装程序有一个MySQL数据库和一个Microsoft SQLserver数据库。我为两个数据库的事务数据源创建了2个JNDI(tomcat-7)资源(请参阅我的META-INF/context.xml) 我调用了com.my.AService.create(obj)。它是一种将引发异常以测试回滚是否有效的方法。在测试结束时,我可以在日志中看到一条回滚消息。但是当我检查数据库时,我看到了应该回滚的提交记录。(请
2014-03-06 11:42:06,103 DEBUG [org.springframework.transaction.interceptor.RuleBasedTransactionAttribute] - <Applying rules to determine whether transaction should rollback on java.lang.NullPointerException>
2014-03-06 11:42:06,103 DEBUG [org.springframework.transaction.interceptor.RuleBasedTransactionAttribute] - <Winning rollback rule is: RollbackRuleAttribute with pattern [Exception]>
...
2014-03-06 11:42:06,104 DEBUG [org.springframework.transaction.jta.JtaTransactionManager] - <Initiating transaction rollback>
2014-03-06 11:42:06,105 DEBUG [org.springframework.transaction.jta.JtaTransactionManager] - <Triggering afterCompletion synchronization>
2014-03-06 11:42:06,105 DEBUG [org.springframework.transaction.support.TransactionSynchronizationManager] - <Clearing transaction synchronization>
我的WEB-INF/config/root-context.xml中的Spring配置:
<jee:jndi-lookup id="mysqlDataSourceTx" jndi-name="java:comp/env/jdbc/mysqldb" expected-type="javax.sql.DataSource"/>
<jee:jndi-lookup id="dataSourceTx" jndi-name="java:comp/env/jdbc/mssqldb" expected-type="javax.sql.DataSource"/>
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionSynchronizationRegistryName" value="java:comp/env/TransactionSynchronizationRegistry"/>
<property name="transactionManagerName" value="java:comp/UserTransaction"/>
</bean>
<bean id="adDao" class="com.my.dao.ADDaoJdbcImpl">
<property name="dataSource">
<ref bean="dataSourceTx"/>
</property>
</bean>
<bean id="amDao" class="com.my.dao.AMDaoJdbcImpl">
<property name="dataSource">
<ref bean="dataSourceTx"/>
</property>
</bean>
<bean id="aDao" class="com.my.dao.AJdbcImpl">
<property name="dataSource">
<ref bean="dataSourceTx"/>
</property>
</bean>
<bean id="fService" class="com.my.service.FService">
<property name="dataSource">
<ref bean="mysqlDataSourceTx"/>
</property>
</bean>
<bean id="bDao" class="com.my.dao.BDaoJdbcImpl">
<property name="dataSource">
<ref bean="dataSourceTx"/>
</property>
</bean>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="read*" read-only="true"/>
<tx:method name="create*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="update*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="delete*" propagation="REQUIRED" rollback-for="Exception"/>
</tx:attributes>
</tx:advice>
<tx:advice id="txDaoAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="read*" read-only="true"/>
<tx:method name="find*" read-only="true"/>
<tx:method name="*" propagation="REQUIRED" rollback-for="Exception"/>
</tx:attributes>
</tx:advice>
<tx:advice id="txGeneralAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" rollback-for="Exception"/>
</tx:attributes>
</tx:advice>
<!-- use proxy-target-class to force use of CGLIB -->
<aop:config proxy-target-class="true">
<aop:pointcut id="aServiceOperation" expression="execution(* com.my.service.AService.*(..))" />
<aop:pointcut id="daoOperation3" expression="execution(* com.my.dao.AJdbcImpl.*(..))" />
<aop:pointcut id="daoOperation4" expression="execution(* com.my.dao.BDaoJdbcImpl.*(..))" />
<aop:pointcut id="fServiceOperation" expression="execution(* com.my.service.FService.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="aServiceOperation"/>
<aop:advisor advice-ref="txDaoAdvice" pointcut-ref="daoOperation3"/>
<aop:advisor advice-ref="txDaoAdvice" pointcut-ref="daoOperation4"/>
<aop:advisor advice-ref="txGeneralAdvice" pointcut-ref="fServiceOperation"/>
</aop:config>
<!-- NO tx:annotation-driven -->
<bean id="aService" class="com.my.service.AService">
</bean>
com.my.service.AService的部分代码:
package com.my.service;
// omitted import statements
public class AService implements IAService {
@Autowired AJdbcImpl aDao;
@Autowired BDaoJdbcImpl bDao;
@Autowired FService fService;
public AService() {
// empty
}
@Override
public List<ARecord> readAll() {
return aDao.findAll();
}
@Override
public Asset create(ARecord obj) {
String name = bDao.getNameFromId(obj.getBRecordId());
// create my_sql record
int new_mysql_id = fService.createTRecord(name);
obj.setTRecordId(new_mysql_id);
// create MS Sqlserver record
int new_sqlserver_id = aDao.create(obj);
obj.setId(new_sqlserver_id);
// raise an exception to test rollback
String nullString = null;
int BLOW_UP_HERE_WITH_NULL_POINTER_REFERENCING = nullString.length();
return obj;
}
//
// omitted update() , and delete() code
//
}
package com.my.service;
// omitted import statements
public interface IAService {
List<ARecord> readAll();
Asset create(ARecord obj);
//
// omitted update() , and delete()
}
package com.my.service;
//省略的导入语句
公共类AService实现iService{
@自动接线AJdbcImpl aDao;
@自连线BDaoJdbcImpl bDao;
@自动连线服务;
公共服务{
//空的
}
@凌驾
公共列表readAll(){
返回aDao.findAll();
}
@凌驾
公共资产创建(ARecord obj){
String name=bDao.getNameFromId(obj.getbrecordd());
//创建我的sql记录
int new\u mysql\u id=fsservice.createTreRecord(名称);
对象setTRecordId(新的mysql\u id);
//创建MS Sqlserver记录
int new_sqlserver_id=aDao.create(obj);
对象setId(新的sqlserver\u id);
//引发异常以测试回滚
字符串nullString=null;
int BLOW_UP_HERE_与_NULL_指针_referenting=nullString.length();
返回obj;
}
//
//省略了update()和delete()代码
//
}
com.my.service.IAService的部分代码:
package com.my.service;
// omitted import statements
public class AService implements IAService {
@Autowired AJdbcImpl aDao;
@Autowired BDaoJdbcImpl bDao;
@Autowired FService fService;
public AService() {
// empty
}
@Override
public List<ARecord> readAll() {
return aDao.findAll();
}
@Override
public Asset create(ARecord obj) {
String name = bDao.getNameFromId(obj.getBRecordId());
// create my_sql record
int new_mysql_id = fService.createTRecord(name);
obj.setTRecordId(new_mysql_id);
// create MS Sqlserver record
int new_sqlserver_id = aDao.create(obj);
obj.setId(new_sqlserver_id);
// raise an exception to test rollback
String nullString = null;
int BLOW_UP_HERE_WITH_NULL_POINTER_REFERENCING = nullString.length();
return obj;
}
//
// omitted update() , and delete() code
//
}
package com.my.service;
// omitted import statements
public interface IAService {
List<ARecord> readAll();
Asset create(ARecord obj);
//
// omitted update() , and delete()
}
package com.my.service;
//省略的导入语句
公共接口iService{
List readAll();
资产创建(ARecord obj);
//
//省略了update()和delete()
}
发布更完整的日志,特别是从org.springframework.transaction
发布日志可能会有所帮助。到底基地里有什么记录?在我的最终解决方案中,我使用了atomikos而不是jotm。JOTM似乎已经多年没有更新了。
package com.my.service;
// omitted import statements
public interface IAService {
List<ARecord> readAll();
Asset create(ARecord obj);
//
// omitted update() , and delete()
}