SpringBoot事务失效的8种场景
2026/9/15 22:52:49 网站建设 项目流程

SpringBoot让事务管理变得极其简单,一个@Transactional注解似乎就能搞定一切。但实际开发中,事务莫名其妙不回滚的情况比比皆是。我整理了8种最常见的失效场景,每一个都是血泪教训。

一、方法不是public

@Transactional基于AOP代理,Spring默认只对public方法生效。如果你把注解加在private、protected或包级方法上,事务不会启动,也不会报错。很多人写了一个私有方法加事务,调了半天发现根本没生效。解决:确保事务方法为public。

二、自调用:this调用本类方法

这是最经典的坑。在同一个类中,方法A调用方法B,即使B加了@Transactional,事务也不会生效。因为自调用走的是原始对象,而不是代理对象。解决:把B方法抽到另一个Bean中,或者注入自身代理,或者用AopContext.currentProxy()

三、异常被捕获,没有抛出

方法内部try-catch把异常吞了,事务管理器感知不到异常,自然不回滚。解决:捕获后要么重新抛出,要么手动TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()

四、异常类型不对

Spring默认只对RuntimeExceptionError回滚。如果你抛的是检查异常(如IOException),事务不会回滚。解决:使用@Transactional(rollbackFor = Exception.class)

五、数据库引擎不支持事务

MySQL的MyISAM引擎不支持事务,如果你建表时用了它,注解再正确也没用。解决:使用InnoDB引擎。这个坑在老旧项目中尤其常见。

六、多线程调用

事务信息保存在ThreadLocal中,新线程无法获取父线程的事务上下文。如果你在事务方法中开新线程执行数据库操作,新线程的操作不在同一个事务里。解决:避免在事务中开线程,或者把事务逻辑放在线程内部独立处理。

七、传播行为配置错误

@Transactional(propagation = Propagation.NOT_SUPPORTED)会挂起当前事务。如果你在需要事务的方法上配了SUPPORTSNOT_SUPPORTED,自然不会回滚。解决:理解传播行为,默认REQUIRED通常够用。

八、Bean未被Spring管理

自己new出来的对象,即使方法上有@Transactional,也不会有代理,事务失效。比如在工具类里直接new Service()调用。解决:确保事务Bean由Spring容器管理,通过依赖注入获取。

额外补充:只读事务中写操作

@Transactional(readOnly = true)只是提示,不一定阻止写入,但某些数据库驱动会拒绝写操作,导致异常。不要把只读事务用在写方法上。

如何排查?

开启事务调试日志:logging.level.org.springframework.transaction=DEBUG。观察日志中有没有 “Creating new transaction” 或 “Participating in existing transaction”。如果没有,说明事务根本没生效。

结语

事务失效的原因大多不是Spring的bug,而是我们对代理机制、异常体系和传播行为的理解不够深。记住一个原则:事务是基于代理的,代理生效的前提是外部调用、public方法、异常抛出、Bean被管理。把这四点刻在脑子里,能避开90%的坑。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询