失效八连,全是原理推出来的
有了第 6、8 篇的原理,失效场景不需要背表格——每一种都能指着机制推出来:
一、自调用:this 绕过代理,拦截器没机会上桌——开篇的标本,解法三条(@Lazy 自注入、拆类、exposeProxy)。
二、方法不是 public:Spring 事务切面只处理 public 方法,protected、包级、private 上的 @Transactional 被静默忽略——不报错、无警告,最阴的一种。
三、异常被 catch 吞了:拦截器靠「方法抛出异常」触发回滚,你把异常吃掉,它以为岁月静好照常 commit。非要 catch 就在块里调 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly() 标记回滚,或者重抛。
四、rollbackFor 没配:默认只回滚 RuntimeException 和 Error,受检异常照样提交——上篇讲过的默认规则坑。
五、对象不受容器管:自己 new 的 Service 没有代理,注解纯属装饰品。事务的前提是「从容器拿代理对象来用」。
六、传播行为配错:挂了 NOT_SUPPORTED 的方法以非事务方式执行;REQUIRES_NEW 的内外事务互相独立——想要「一起回滚」却配成了「各回各的」,第 10 篇细拆。
七、跨线程:事务上下文绑在 ThreadLocal 上,新开线程拿不到——异步方法里的数据库操作各用各的连接,永远不在同一个事务里。
八、存储引擎不支持:MySQL 的 MyISAM 引擎不支持事务,只有 InnoDB 支持——老项目迁移时的经典暗坑。
排查心法:三步定位
遇到「事务没生效」按顺序查:第一步,Bean 是不是容器管理的代理——AopUtils.isAopProxy(bean) 见分晓;第二步,调用路径是否经过代理——没有 this 自调用、方法是 public;第三步,异常是否真的飞出了事务方法边界——没被 catch、类型命中 rollbackFor。八种失效,九成死在这三步里。
单层事务说完了。多个事务方法嵌套调用时谁听谁的?传播行为七式,下一篇排兵布阵。
评论 (0)