Administrator
Administrator
发布于 2024-07-17 / 54 阅读
0
0

用try..catch捕获了顶层Exception就一定不会影响外部方法吗?

15d1dceaa684147a7cf9a2170f92a828

结论: 并不是!请看:

@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)。

如何解决?

  1. 将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方法中的逻辑。

  1. 在B中捕获异常使得异常不影响B对应子事务的回滚

这个就不解释了。


评论