SpringBoot事务失效的8个场景,你中招了吗
场景一方法不是publicSpring的声明式事务基于动态代理而代理只能拦截public方法。你把Transactional标在private、protected或包级方法上Spring连看都不看一眼。非public方法上的事务注解就像贴在墙上的符咒好看不中用。改成public或者用编程式事务别跟框架较劲。场景二同类内部调用你在Service的A方法里调用本类的B方法B方法标了Transactional。你以为B会开事务实际上调用走的是this不是代理对象。自调用是事务失效的头号杀手代理根本没机会插手。解法有三注入自己、用AopContext、或者把B抽到另一个Service。推荐抽出去干净利落。场景三异常被吞掉你在事务方法里try-catch了异常然后只打印日志不抛出。Spring怎么知道要回滚异常是回滚的号角你把号角掐了事务自然装聋作哑。要么在catch里重新抛出要么手动TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()。别让异常无声无息地消失。场景四异常类型不对默认情况下Spring只对RuntimeException和Error回滚。你抛了个IOException还是受检异常事务管理器眼皮都不抬。受检异常不是回滚的通行证除非你明确指定。加Transactional(rollbackFor Exception.class)一劳永逸。别省这几个字符省出的是生产事故。场景五事务传播行为搞错默认传播是REQUIRED但如果你在已有事务的方法里调用另一个标了NOT_SUPPORTED或NEVER的方法事务就断了。传播行为是事务的交通规则闯了红灯回滚就堵在路上。搞清楚每个方法的传播语义别让内层方法把外层事务架空。场景六数据库引擎不支持你用的是MyISAM不是InnoDB。MyISAM压根不支持事务你加再多注解也是对牛弹琴。数据库引擎是事务的地基地基不牢注解再多也是空中楼阁。建表时确认ENGINEInnoDB别等数据乱了才拍大腿。场景七多数据源未指定事务管理器项目里配了两个数据源你只写了TransactionalSpring不知道该用哪个事务管理器。结果要么报错要么事务挂在错误的数据源上。多数据源下事务管理器必须指名道姓否则它左右为难最后谁也不管。用Transactional(transactionManager xxxTransactionManager)明确指定。场景八缓存或异步干扰你在Transactional方法上又加了Cacheable或Async。缓存代理和异步代理可能先于事务代理执行导致事务上下文丢失。多个切面叠加执行顺序就是生死顺序。尽量别把事务和缓存、异步混在一个方法上拆开各司其职。千里之堤溃于蚁穴。一个事务失效可能让整晚的批处理变成脏数据制造机。理解代理机制敬畏传播行为盯紧异常类型才是事务稳定的三板斧。别等生产环境报警了才翻文档那时你已经在写事故报告了。把这八个场景刻在脑子里下次加Transactional时多问一句我的事务真的会回滚吗