为什么抛出 NullPointerException 后 @Transactional 不回滚?

Why doesn't @Transactional roll back after NullPointerException is thrown?

我有一个可以抛出 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)

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

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