Spring事务失效在哪些复杂场景下会频繁发生?

摘要:Spring 事务失效是日常开发中非常常见的问题,核心原因是 Spring 声明式事务的实现依赖 AOP 动态代理,一旦代理机制被破坏或不满足事务触发条件,事务就会失效。下面我会逐一讲解最常见的失效场景、原因和解决方案,内容由浅入深,方便你
Spring 事务失效是日常开发中非常常见的问题,核心原因是 Spring 声明式事务的实现依赖 AOP 动态代理,一旦代理机制被破坏或不满足事务触发条件,事务就会失效。下面我会逐一讲解最常见的失效场景、原因和解决方案,内容由浅入深,方便你理解和排查。 一、常见的事务失效场景及解决方案 1. 方法不是 public 修饰 原因:Spring 事务管理器(TransactionInterceptor)只会拦截 public 方法,这是因为 Spring AOP 基于 JDK 动态代理时,只能代理接口的 public 方法;即使是 CGLIB 代理,Spring 也做了限制(源码中会检查方法修饰符)。 示例(失效代码): @Service public class UserService { @Transactional private void addUser(String username) { // private 方法,事务失效 // 数据库操作 } } 解决方案:将方法改为 public 修饰: @Service public class UserService { @Transactional public void addUser(String username) { // 改为 public // 数据库操作 } } 2. 同一个类中方法内部调用 原因:Spring 事务通过代理对象实现,若在同一个类中,普通方法调用加了 @Transactional 的方法,本质是直接调用目标对象的方法,而非代理对象,AOP 无法拦截,事务失效。 示例(失效代码): @Service public class UserService { // 普通方法 public void saveUser(String username) { // 内部调用事务方法,事务失效 addUser(username); } @Transactional public void addUser(String username) { // 数据库操作 } } 解决方案: 方案1(推荐):将事务方法抽取到另一个 Service 类,通过依赖注入调用(走代理); 方案2:自注入代理对象,通过代理对象调用(注意循环依赖问题): @Service public class UserService { // 自注入代理对象(Spring 4.3+ 支持,或通过 ApplicationContext 获取) @Autowired private UserService userService; public void saveUser(String username) { // 通过代理对象调用,事务生效 userService.addUser(username); } @Transactional public void addUser(String username) { // 数据库操作 } } 3. 事务注解属性配置错误 原因:@Transactional 的属性配置不符合业务场景,导致事务不生效或回滚异常。 常见错误配置: propagation = Propagation.NOT_SUPPORTED(不支持事务,会挂起当前事务); propagation = Propagation.SUPPORTS(仅当有事务时才生效,无事务则不使用事务); rollbackFor 未配置,默认只回滚 RuntimeException 和 Error,检查异常(如 SQLException)不会触发回滚。
阅读全文