@Transactional注解事务失效的八种原因分析
@Transactional是一种基于注解管理事务的方式,spring通过动态代理的方式为目标方法实现事务管理的增强。
@Transactional使用起来方便,但也需要注意引起@Transactional失效的场景,本文总结了七种情况,下面进行逐一分析。
1、异常被捕获后没有抛出
当异常被捕获后,并且没有再抛出,那么deleteUserA是不会回滚的。
@Transactional public void deleteUser() { userMapper.deleteUserA(); try { int i = 1 / 0; userMapper.deleteUserB(); } catch (Exception e) { e.printStackTrace(); } }
2、抛出非运行时异常
异步虽然抛出了,但是抛出的是非RuntimeException类型的异常,依旧不会生效。
@Transactional public void deleteUser() throws MyException{ userMapper.deleteUserA(); try { int i = 1 / 0; userMapper.deleteUserB(); } catch (Exception e) { throw new MyException(); } }
如果指定了回滚异常类型为Exception,那么就可以回滚非RuntimeException类型异常了。
@Transactional(rollbackFor = Exception.class)
3、方法内部直接调用
如果先调用deleteUser(),那么deleteUserA()是不会回滚的,其原因就是@Transactional根本没生成代理,如果直接调用deleteUser2()那么没问题,deleteUserA()会回滚。
public void deleteUser() throws MyException{ deleteUser2(); } @Transactional public void deleteUser2() throws MyException{ userMapper.deleteUserA(); int i = 1 / 0; userMapper.deleteUserB(); }
修改方式,把当前类自己注入一下调用即可。
@Service public class UserService { @Autowired private UserMapper userMapper; //自己注入自己 @Autowired UserService userService; public void deleteUser() throws MyException{ userService.deleteUser2(); } @Transactional public void deleteUser2() throws MyException{ userMapper.deleteUserA(); int i = 1 / 0; userMapper.deleteUserB(); } }
4、新开启一个线程
如下的方式deleteUserA()也不会回滚,因为spring实现事务的原理是通过ThreadLocal把数据库连接绑定到当前线程中,新开启一个线程获取到的连接就不是同一个了。
@Transactional public void deleteUser() throws MyException{ userMapper.deleteUserA(); try { //休眠1秒,保证deleteUserA先执行 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(() -> { int i = 1/0; userMapper.deleteUserB(); }).start(); }
5、注解到private方法上
idea直接会给出提示Methods annotated with ‘@Transactional’ must be overridable ,原理很简单,private修饰的方式,spring无法生成动态代理。
@Transactional private void deleteUser() throws MyException{ userMapper.deleteUserA(); int i = 1/0; userMapper.deleteUserB(); }
6、数据库本身不支持
mysql数据库,必须设置数据库引擎为InnoDB。
7、事务传播属性设置错误
注意传播属性的设置,比如设置了:PROPAGATION_NOT_SUPPORIED(以非事务的方式执行,如果当前有事务则把当前事务挂起)。
8、操作数据库使用了truncate关键字
整个业务里面只要有 truncate 就会导致事务回滚失效
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!