ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Spring事务失效的8种场景,你踩过几个?

Spring事务失效的8种场景,你踩过几个? 刚工作时我写了一个转账接口加了Transactional测试时一切正常。上线后用户反馈“钱扣了对方没到账。”我查了半天日志才发现异常被捕获后没有抛出事务根本没回滚。那一刻我才明白Transactional不是万能护身符用错了地方它就是一纸空文。下面这8种场景是Spring事务失效的高发区。看看你踩过几个1. 方法不是publicSpring AOP默认基于代理而代理只能拦截public方法。如果你把Transactional加在private、protected或包级方法上事务不会生效。解决办法很简单确保事务方法用public修饰。如果确实需要非public可以考虑使用AspectJ模式。2. 自调用这是最常见的坑。同一个类中方法A调用方法B即使B有Transactional事务也不会生效。因为调用走的是this而不是代理对象。解决办法把B方法抽到另一个类中或者注入自己Autowired private MyService self;用self.B()调用。3. 异常被捕获没有抛出默认情况下Spring只在遇到RuntimeException和Error时回滚。如果你在事务方法里try-catch了异常并且没有重新抛出Spring会认为一切正常自然不回滚。正确做法捕获后要么抛出运行时异常要么手动设置TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()。4. 抛出的异常类型不对Spring默认只回滚运行时异常。如果你抛出的是IOException、SQLException等检查异常事务不会回滚。解决办法在Transactional上指定rollbackFor Exception.class让所有异常都触发回滚。5. 数据库引擎不支持事务如果你用的是MySQL的MyISAM引擎它根本不支持事务加再多注解也没用。建表时一定要用InnoDB。同样某些NoSQL数据库也不支持事务。先确认底层存储是否支持。6. 事务传播行为配置错误Transactional(propagation Propagation.NOT_SUPPORTED)会挂起当前事务以非事务方式执行。如果你误用了NEVER、NOT_SUPPORTED等事务自然不生效。大多数业务场景用默认的REQUIRED即可。理解传播行为才能避免配置错误。7. 多线程调用Spring事务的上下文存储在ThreadLocal中只在当前线程有效。如果你在事务方法里开了新线程去执行数据库操作新线程不在事务范围内。解决办法把事务逻辑放在主线程或者使用分布式事务、编程式事务手动控制。8. 类没有被Spring管理如果类没有加Service、Component等注解或者你是通过new创建的对象Spring不会为它生成代理Transactional自然失效。确保你的Bean由Spring容器管理并且注入的是代理对象。总结Transactional看似简单背后却涉及代理机制、异常体系、线程模型和数据库特性。用之前先问自己方法是不是public有没有自调用异常抛对了吗类被Spring管了吗把这几个问题想清楚大部分事务失效都能避免。如果已经踩了坑别慌。先看日志确认事务有没有开启再用TransactionSynchronizationManager.isActualTransactionActive()判断当前线程是否在事务中。调试几次你就能摸清它的脾气。事务是数据一致性的最后一道防线千万别让它形同虚设。
返回列表