请列举 Spring 事务管理失效的典型场景,并简要说明各场景导致事务失效的根本机制。
考察说明
考察对 Spring 事务底层实现机制(代理、异常回滚、传播行为)的理解,以及能否识别常见误用场景。
回答思路
- 【回答框架 1】Spring 事务默认通过 AOP 代理实现,核心是事务管理器对连接的控制。事务失效的根本原因通常是代理未生效、异常未触发回滚规则或事务传播配置不当。
- 【回答框架 2】代理未生效的典型场景:方法被 private/final 修饰,或通过 this 调用同类方法,此时调用不会经过代理对象,导致事务拦截器不执行;Spring Boot 1.4 后默认使用 CGLIB 代理,但私有方法仍无法代理。
- 【回答框架 3】异常处理不当:@Transactional 默认只回滚 RuntimeException 和 Error,受检异常(如 Exception)默认不回滚,需通过 rollbackFor 显式指定;若在方法内捕获异常并吞掉,事务不会回滚。
- 【回答框架 4】传播行为配置错误:如 PROPAGATION_NOT_SUPPORTED 会挂起当前事务,以非事务方式运行;REQUIRES_NEW 会挂起外部事务,若外部事务回滚不影响新事务提交,可能导致整体一致性被破坏。
- 【回答框架 5】其他场景:数据库引擎不支持事务(如 MyISAM)、事务方法被多线程调用(各自独立连接)、事务管理器未正确配置或数据源未代理等。
- 【关键点 1】private、final 方法或 this 调用导致代理失效是常见失效原因。
- 【关键点 2】默认仅回滚 RuntimeException 和 Error,受检异常需配置 rollbackFor。
- 【关键点 3】方法内捕获异常并吞掉会使事务无法感知异常而继续提交。
- 【关键点 4】不恰当的传播行为(如 NOT_SUPPORTED、REQUIRES_NEW)会改变事务边界。
- 【关键点 5】存储引擎不支持事务或事务管理器配置错误也导致失效。
- 【易错点 1】不要认为所有异常都会自动回滚,必须明确 Spring 的默认回滚策略。
- 【易错点 2】多线程调用事务方法时,每个线程独立事务,不能期望共享同一事务。
- 【易错点 3】事务管理基于代理,若绕过代理(如直接调用实现类方法)则完全失效。