【问题标题】:Why doesn't @Transactional roll back after NullPointerException is thrown?为什么在抛出 NullPointerException 后 @Transactional 不回滚?
【发布时间】:2020-10-01 12:30:32
【问题描述】:

我有一个可以抛出 NullPointerException 的方法。该方法标记为@Transactional

我的代码结构如下:

public void outer() {
    try {
        inner();
    } catch (Exception e) {
        // exception caught
    }     
}

@Transactional
public void inner() {
    database.saveStuff();
    throw new NullPointerException();
}

运行上述代码后,inner() 内部的数据库更新不会回滚。什么可能导致这样的问题?

根据我的理解,如果异常对注释“可见”,则应回滚数据库操作。在这种情况下意味着inner() 方法被标记为@Transactional 并抛出异常而不是捕获它。

可能还值得一提的是,方法 outer() 也在另一个 @Transactional 方法中调用,而该方法又在 try catch 中调用。但是,该方法看不到异常,因为它被捕获在 outer() 中,因此根据我的理解,它应该无关紧要。

我试图在网上搜索答案,但所有答案似乎都是关于已检查的异常(例如java.lang.Exception)不会自动回滚。因为NullPointerExceptionRuntimeException 的子类,所以这里不应该成为问题。

我的团队中也有人建议使用这组注释,但没有任何区别:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Transactional(rollbackFor=Exception.class, isolation=Isolation.READ_COMMITTED)

【问题讨论】:

    标签: java spring transactions


    【解决方案1】:

    因为你是直接打电话给inner()。 Spring AOP 仅适用于 bean 方法,因为直接调用 inner() 不会被代理,也不会添加拦截器。

    正如您提到的,outer 方法是从具有 @Transactional 的方法调用的,因此,您应该删除 try-catch 或重新抛出异常。

    【讨论】:

      猜你喜欢
      • 2013-09-09
      • 1970-01-01
      • 2014-01-24
      • 1970-01-01
      • 1970-01-01
      • 2014-12-18
      • 2014-07-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多