Spring事务的传播机制和常见失效场景有哪些?

2025年 阅读约 10 分钟 面试指南 · Spring Boot面试

深入理解Spring事务传播机制,详解七种传播行为及事务失效的六大常见场景与解决方案。

一句话总结

Spring事务传播机制定义了事务方法间相互调用时的行为,共7种。常见失效场景:方法非public、同类自调用、异常被吞、异常类型不匹配、数据库引擎不支持、未被Spring管理。

初级理解

七种传播行为:

1. REQUIRED(默认):有事务则加入,无则新建 2. REQUIRES_NEW:无论是否有事务,都新建事务,挂起当前事务 3. SUPPORTS:有事务则加入,无则以非事务方式执行 4. NOT_SUPPORTED:以非事务方式执行,挂起当前事务 5. MANDATORY:必须在事务中调用,否则抛异常 6. NEVER:以非事务方式执行,若在事务中则抛异常 7. NESTED:有事务则在嵌套事务中执行(Savepoint),无则新建
一句话总结:REQUIRED加入现有事务,REQUIRES_NEW新建事务,NESTED嵌套事务。

中级深入

常见失效场景:

1. 方法非public:Spring AOP仅拦截public方法

// 失效 @Transactional private void createOrder() { ... } // 正确 @Transactional public void createOrder() { ... }

2. 同类自调用:this.method()绕过代理对象

// 失效 public void methodA() { this.methodB(); // 绕过代理,事务失效 } // 解决:注入自身或使用AopContext.currentProxy()

3. 异常被吞掉:try-catch捕获异常未抛出

4. 异常类型不匹配:默认只回滚RuntimeException

// 正确:指定rollbackFor @Transactional(rollbackFor = Exception.class)
注意:同类自调用是Spring事务失效最常见的原因,一定要避免。

高级拓展

更多失效场景:

5. 数据库引擎不支持:MyISAM不支持事务

6. 未被Spring管理:类未加@Service/@Component,或手动new的对象

REQUIRED vs REQUIRES_NEW vs NESTED:

REQUIRED:加入现有事务(最常用) REQUIRES_NEW:新建事务,挂起当前事务(独立事务) NESTED:嵌套事务,使用Savepoint(外层回滚则内层也回滚) // 例子 @Transactional public void methodA() { // 外层事务 methodB(); // REQUIRED: 加入外层事务 methodC(); // REQUIRES_NEW: 新建独立事务 methodD(); // NESTED: 嵌套事务 }
面试加分项:能说出6种失效场景、三种传播行为的区别,说明你对Spring事务有深入理解。

实战场景

场景:同类自调用导致事务失效

// 问题代码 @Service public class OrderService { public void methodA() { this.methodB(); // 同类自调用,事务失效 } @Transactional public void methodB() { orderMapper.insert(order); int i = 1 / 0; // 异常不会回滚 } } // 解决方案1:注入自身 @Service public class OrderService { @Autowired @Lazy private OrderService self; public void methodA() { self.methodB(); // 通过代理调用 } } // 解决方案2:使用AopContext @Service public class OrderService { public void methodA() { ((OrderService) AopContext.currentProxy()).methodB(); } }

面试模拟

Q:Spring事务失效的常见场景有哪些?

A:六大场景:1. 方法非public;2. 同类自调用(this绕过代理);3. 异常被try-catch吞掉;4. 异常类型不匹配(默认只回滚RuntimeException);5. 数据库引擎不支持(MyISAM);6. 未被Spring管理(手动new的对象)。

Q:REQUIRED和REQUIRES_NEW的区别?

A:REQUIRED会加入现有事务,如果当前没有事务则新建;REQUIRES_NEW无论是否存在事务,都会新建事务,并挂起当前事务。例如方法A调用方法B,如果B是REQUIRED,则B加入A的事务;如果B是REQUIRES_NEW,则B新建事务,A的事务被挂起。