现象:
在Service中有两个方法doTransaction(调用更新方法A、B,在A和B之间抛出RuntimeEx)和callTransaction。callTransaction调用doTransaction。且仅有doTransaction配置上了事务,callTransaction方法不处理任何异常。
在controller中单独调用doTransaction,有异常A是可以回滚的,但是如果在controller中调用callTransaction,doTransaction抛出异常直到controller,发现doTransaction方法中的A方法没有回滚。事务传波机制配置为REQUIRED
配置如下:
spring-mybatis.xml
<!-- 拦截器方式配置事物 --> <tx:advice id="transactionAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="doTransaction" propagation="REQUIRED" rollback-for="java.lang.Exception" /> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="transactionPointcut" expression="execution(* com.forg..service..*(..))" /> <aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice" /> </aop:config>
Service如下
public boolean doTransaction(String p1,String p2){
boolean a = testDAO.doUpdate1(p1);
if(a){
throw new RuntimeException("抛出异常");
}
boolean b = testDAO.doUpdate2(p2);
return a && b;
}
public boolean callTransaction(String p1,String p2){
// try{ return doTransaction(p1,p2); // }catch(Exception e){ // System.out.println("doTransaction_exception!"); // throw new RuntimeException("抛出异常"); // return false;
// } }
调用Controller
public String testTransction(@RequestParam(value="p1",required=true)String p1, @RequestParam(value="p2",required=true) String p2){ if(("p111").equals(p1)){ if(ts.doTransaction(p1, p2)){//这里是可以回滚update1的 return "OK"; } return "NOT OK"; } try { if(ts.callTransaction(p1, p2)){//这里却不可以! return "OK"; } } catch (Exception e) { System.out.println("callTransaction_exception"); } return "NOT OK"; }
请各位大牛帮忙看下,不知道是什么原因导致的?
是到service级别的 ?还是我对事务传播机制理解有误?
下面是日志
直接调用callTransaction
[DEBUG] [org.mybatis.spring.SqlSessionUtils]Creating a new SqlSession kan>plugin... [DEBUG] [org.mybatis.spring.SqlSessionUtils]SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7e10020] was not registered for synchronization because synchronization is not active kan>plugin... kan>plugin... kan>plugin... [DEBUG] [org.mybatis.spring.transaction.SpringManagedTransaction]JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@3ffcfd14] will not be managed by Spring [DEBUG] [com.forg.com.test.update1]==> Preparing: UPDATE t_1 SET CNT = ? WHERE ID =1 [DEBUG] [com.forg.com.test.update1]==> Parameters: p112(String) [DEBUG] [com.forg.com.test.update1]<== Updates: 1 [DEBUG] [org.mybatis.spring.SqlSessionUtils]Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7e10020] 一月 07, 2015 2:25:43 下午 org.apache.catalina.core.StandardWrapperValve invoke 严重: Servlet.service() for servlet [springMVC] in context with path [/forgweb] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: 抛出异常] with root cause java.lang.RuntimeException: 抛出异常 at com.forg.test.service.TransactionTestService.doTransaction(TransactionTestService.java:32)
直接调用 doTransaction
kan>plugin... [DEBUG] [org.mybatis.spring.SqlSessionUtils]Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3ccb117c] kan>plugin... kan>plugin... kan>plugin... [DEBUG] [org.mybatis.spring.transaction.SpringManagedTransaction]JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@3ffcfd14] will be managed by Spring [DEBUG] [com.forg.com.test.update1]==> Preparing: UPDATE t_1 SET CNT = ? WHERE ID =1 [DEBUG] [com.forg.com.test.update1]==> Parameters: p111(String) [DEBUG] [com.forg.com.test.update1]<== Updates: 1 [DEBUG] [org.mybatis.spring.SqlSessionUtils]Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3ccb117c] [DEBUG] [org.mybatis.spring.SqlSessionUtils]Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3ccb117c] [DEBUG] [org.mybatis.spring.SqlSessionUtils]Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3ccb117c] 一月 07, 2015 2:26:27 下午 org.apache.catalina.core.StandardWrapperValve invoke 严重: Servlet.service() for servlet [springMVC] in context with path [/forgweb] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: 抛出异常] with root cause java.lang.RuntimeException: 抛出异常 at com.forg.test.service.TransactionTestService.doTransaction(TransactionTestService.java:32)
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。
根据您的描述,您在使用Spring框架管理事务,并且遇到了一个关于事务回滚的异常行为。首先,让我们澄清几个关键点以更好地理解问题:
事务传播行为:您提到的事务传播机制配置为REQUIRED
。这意味着如果当前存在事务,则方法将会加入到这个事务中;如果不存在,则会创建一个新的事务。
代码示例:您的doTransaction
方法内执行了两个数据库操作(doUpdate1
和doUpdate2
),并且在两者之间抛出了一个未被捕获的RuntimeException
。按照Spring的默认事务规则,当方法中抛出未检查异常(即继承自RuntimeException
的异常)时,应该触发事务回滚。
问题现象:直接调用doTransaction
方法时,如果抛出异常,A方法的操作能够正确回滚。但是,当通过callTransaction
方法间接调用doTransaction
,即使抛出异常,A方法的操作却没有回滚。
针对这个问题,有几个可能的原因:
事务管理器配置问题:确保事务管理器配置正确,并且被正确地应用到了包含doTransaction
方法的服务类上。请检查@Transactional
注解是否正确放置在服务类或方法上,并且确认Spring扫描到了这个配置。
异常被捕获处理:虽然您说callTransaction
不处理任何异常,但请仔细检查是否有其他地方(比如AOP切面、全局异常处理器等)捕获并处理了这个异常,这可能会导致Spring认为事务可以正常提交而不是回滚。
嵌套事务问题:由于callTransaction
没有自己的事务声明(即它没有@Transactional
注解),理论上它应该不会影响到内部调用的doTransaction
方法的事务行为。但如果存在某些特定的AOP配置或者代理设置不当,可能导致事务上下文传递出现问题。
解决建议:
确认@Transactional
注解的使用是否正确无误,包括它的属性设置(如rollbackFor
来指定需要回滚的异常类型,尽管对于未检查异常,默认情况下应当自动回滚)。
检查整个调用链路中是否存在异常被捕获而未向上抛出的情况,确保异常能自然传播到事务管理器。
查看Spring的日志输出,特别是与事务管理相关的日志,这有助于诊断事务开始、提交或回滚的详细过程,以及是否有任何错误或警告信息。
如果以上检查均未发现问题,可能需要更详细的配置信息和代码逻辑来进一步分析问题所在。