英文:
Why doesn't @Transactional roll back after NullPointerException is thrown?
问题
我有一个可能会抛出NullPointerException的方法。该方法标有@Transactional
。
我的代码结构如下:
public void outer() {
try {
inner();
} catch (Exception e) {
// 捕获异常
}
}
@Transactional
public void inner() {
database.saveStuff();
throw new NullPointerException();
}
在运行上述代码后,inner()
中的数据库更新不会被回滚。可能是什么原因导致这种问题?
根据我的理解,如果异常对注解是“可见”的话,数据库操作应该会被回滚。在这种情况下,意味着inner()
方法标有@Transactional
并抛出异常,而不是捕获异常。
值得一提的是,outer()
方法也在另一个@Transactional
方法内部调用,而后者又位于try catch
块内。然而,由于异常在outer()
内部被捕获,所以根据我的理解,它对该方法不可见,因此不应该有影响。
我尝试在网络上寻找答案,但所有的答案似乎都是关于已检查异常(例如java.lang.Exception
)不会自动回滚的情况。因为NullPointerException
是RuntimeException
的子类,所以在这里不应该是问题。
我的团队中有人建议使用这组注解,但这并没有产生任何影响:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Transactional(rollbackFor=Exception.class, isolation=Isolation.READ_COMMITTED)
英文:
I have a method which can throw a NullPointerException. The method is marked with @Transactional
.
My code structure is as follows:
public void outer() {
try {
inner();
} catch (Exception e) {
// exception caught
}
}
@Transactional
public void inner() {
database.saveStuff();
throw new NullPointerException();
}
After running the above code, the database updates inside inner()
are not rolled back. What could cause such problem?
As per my understanding, the database actions should be rolled back if the exception is "visible" to the annotation. In this case meaning that the inner()
method is marked with @Transactional
and throws the exception instead of catching it.
It might also be worth mentioning that the method outer()
is also called inside another @Transactional
method, which in turn is inside a try catch
. However, the exception is not visible to that method because it's caught inside outer()
, so as per my understanding it shouldn't matter.
I tried to search for answers on the web, but all the answers seem to be about checked Exceptions (e.g. java.lang.Exception
) not automatically being rolled back. Because NullPointerException
is a subclass of RuntimeException
, that shouldn't be an issue here.
Somebody in my team also suggested to use this cluster of annotations, but it didn't make any difference:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Transactional(rollbackFor=Exception.class, isolation=Isolation.READ_COMMITTED)
答案1
得分: 2
因为你直接调用了inner()
。Spring AOP 只对bean方法起作用,因为直接调用了inner()
,它不会被代理,拦截器也不会被添加。
正如你提到的,outer
方法是从一个带有@Transactional
的方法中调用的,所以你应该要么移除try-catch
,要么重新抛出异常。
英文:
Because you are calling inner()
directly. Spring AOP only works with bean method since inner()
is called directly it won't be proxied and the interceptors are not added.
As you mentioned the outer
method is called from a method with @Transactional
So, you should either remove the try-catch
or rethrow the exception.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论