一句话总结
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的事务被挂起。