原标题:技术贴 | Spring事务不回滚问题排查
本技术贴是我司技术小哥在开发新项目中遇到的问题时的分析及思考,学霸的人生学无止境。
01
问题描述
在新项目的开发中遇到一个奇葩的问题:方法添加了事务后数据库不回滚,而且不是每一个方法都不回滚,是有的方法回滚,有的不回滚。
02
问题背景
新项目使用SpringBoot2.0+Mybatis框架,启用事务的方式是在类的方法上使用@Transactional注解的方式来启用事务的
(旧项目直接在类上面加@Transactional,该类下所有方法都支持事务,考虑到一些查询方法是不需要事务的,这样会影响性能,所以改为在方法上添加@Transactional注解,所以旧项目事务没有出现问题)。
03
排查问题
经过对比发现:
回滚的方法都是由controller直接调用有@Transactional注解的,而不回滚的方法都是由controller调用了方法A(该方法没有声明事务),再由方法A调用方法B(该方法声明了事务)
例如:测试类TestController
TestOneServiceImpl
TestController类中的test()方法调用了
TestOneServiceImpl中的testFunctionOne() 方法
testFunctionOne()方法调用了 testFunctionTwo()方法(启用了事务) 。
如果事务起作用,则user对象中userName字段不会更改
首先查询userName值
调用 test()方法 查询数据库
发现userName值已被更改 ,testFunctionTwo()方法中的事务没起作用
在test()方法中直接调用testFunctionTwo()方法
调用前userName值
调用后userName值
发现userName值未被更改 ,testFunctionTwo()方法中的事务起作用了,数据库回滚,复现了项目中的问题。
经过查询spring官网 发现原文
In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual transaction at runtime even if the invoked method is marked with @Transactional. Also, the proxy must be fully initialized to provide the expected behaviour so you should not rely on this feature in your initialization code, i.e. @PostConstruct.
大体意思是 默认的代理模式下,只有被代理拦截的外部方法。这意味着,自调用即类内部方法调用本类内部的其他方法并不会引起事务行为(即使该方法被@Transactional注解标记)。
由上可见,新项目中事务不回滚的原因已被找到。
04
解决方案
无脑方式:
将需要事务的方法提到另一个类中
官方解决方案:
使用AspectJ[JL1] 代理模式替代默认代理(暂未实现)
通过初始化方法在目标对象中注入代理对象
调用前userName值
调用后userName值
小结
经过这次事件 认真学习了一下spring事务的注意事项总结如下:
默认代理模式下 只有public修饰的方法事务才起作用, private protected 包内可见方法即使用@Transactional声明了事务,不会出错 也不会起作用(可以使用AspectJ代理来解决)
任何 RuntimeException 抛出时触发回滚, 检查异常抛出时不会回滚。如果想实现抛出检查异常回滚需在@Transactional中添加属性rollbackFor 指定需要回滚的异常类 norollbackFor 自定义不回滚异常
默认的代理模式下,只有被代理拦截的外部方法才事务才回起作用。自调用即类内部方法调用本类内部的其他方法并不会引起事务行为(即使该方法被@Transactional注解标记)。 如果想实现自调用 需更换代理模式 使用AspectJ代理来解决
异常如果被catch住了并且没有抛出 事务是不会起作用的
感谢李斌对此次故障排查做出的贡献
参考文献:Spring官方文档
https://docs.spring.io/spring/docs/4.3.13.RELEASE/spring-framework-reference/htmlsingle/#transaction-declarative-annotations返回搜狐,查看更多
责任编辑: