结论: 并不是!请看:
@Transactional
public void a() {
// a 方法的业务逻辑
try {
self.b(); // 确保通过代理调用 b 方法
} catch (Exception e) {
// 处理 b 方法中的异常
}
}
@Transactional
public void b() {
throw new RuntimeException();
}
如果存在事务嵌套,A套B, A和B都标记了事务,事务传播类型为缺省值(即B事务会加入到A事务中形成一个事务),那么即使A中对B方法try…catch了,若B发生异常,A依然会报错(Transaction rolled back because it has been marked as rollback-only)。
如何解决?
- 将B的传播类型改为REQUIRES_NEW
@Transactional
public void a() {
// a 方法的业务逻辑
try {
self.b(); // 确保通过代理调用 b 方法
} catch (Exception e) {
// 处理 b 方法中的异常
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void b() {
throw new RuntimeException();
}
这种方式为什么能够解决问题呢?因为B事务会作为一个独立事务,回滚也不会影响A事务。本质上,其实是在开始B事务前设置了一个 SavePoint
(可以看这篇文章比较浅显易懂),B事务发生异常,将回滚到定义的 SavePoint
上,即b方法执行前,从而不影响a方法中的逻辑。
- 在B中捕获异常使得异常不影响B对应子事务的回滚
这个就不解释了。