gpt4 book ai didi

java - UnexpectedRollbackException - 完整的场景分析

转载 作者:IT老高 更新时间:2023-10-28 13:51:30 25 4
gpt4 key购买 nike

我对这个异常的了解来自 Spring 的 documentation以及一些论坛帖子,其中结霜的开发人员粘贴了大量的堆栈跟踪,但没有回复。

来自 Spring 的文档:

Thrown when an attempt to commit a transaction resulted in an unexpected rollback

我想一劳永逸地理解

  1. 究竟是什么原因造成的?

    • 回滚发生在哪里?在应用服务器代码还是在数据库中?
    • 是否是由于特定的底层异常(例如 java.sql.* 中的某些异常)引起的?
    • 它与 hibernate 有关吗?它与 Spring Transaction Manager(在我的情况下不是 JTA)有关吗?
  2. 如何避免?有什么最佳做法可以避免吗?

  3. 如何调试它?它似乎很难重现,有什么行之有效的解决方法吗?

最佳答案

我发现这是在回答剩下的问题:https://jira.springsource.org/browse/SPR-3452

I guess we need to differentiate between 'logical' transaction scopes and 'physical' transactions here...

What PROPAGATION_REQUIRED creates is a logical transaction scope for each method that it gets applied to. Each such logical transaction scope can individually decide on rollback-only status, with an outer transaction scope being logically independent from the inner transaction scope. Of course, in case of standard PROPAGATION_REQUIRED behavior, they will be mapped to the same physical transaction. So a rollback-only marker set in the inner transaction scope does affect the outer transaction's chance to actually commit. However, since the outer transaction scope did not decide on a rollback itself, the rollback (silently triggered by the inner transaction scope) comes unexpected at that level - which is why an UnexpectedRollbackException gets thrown.

PROPAGATION_REQUIRES_NEW, in contrast, uses a completely independent transaction for each affected transaction scope. In that case, the underlying physical transactions will be different and hence can commit or rollback independently, with an outer transaction not affected by an inner transaction's rollback status.

PROPAGATION_NESTED is different again in that it uses a single physical transaction with multiple savepoints that it can roll back to. Such partial rollbacks allow an inner transaction scope to trigger a rollback for its scope, with the outer transaction being able to continue the physical transaction despite some operations having been rolled back. This is typically mapped onto JDBC savepoints, so will only work with JDBC resource transactions (Spring's DataSourceTransactionManager).

To complete the discussion: UnexpectedRollbackException may also be thrown without the application ever having set a rollback-only marker itself. Instead, the transaction infrastructure may have decided that the only possible outcome is a rollback, due to constraints in the current transaction state. This is particularly relevant with XA transactions.

As I suggested above, throwing an exception at the inner transaction scope, then catching that exception at the outer scope and translating it into a silent setRollbackOnly call there should work for your scenario. A caller of the outer transaction will never see an exception then. Since you only worry about such silent rollbacks because of special requirements imposed by a caller, I would even argue that the correct architectural solution is to use exceptions within the service layer, and to translate those exceptions into silent rollbacks at the service facade level (right before returning to that special caller).

Since your problem is possibly not only about rollback exceptions, but rather about any exceptions thrown from your service layer, you could even use standard exception-driven rollbacks all the way throughout you service layer, and then catch and log such exceptions once the transaction has already completed, in some adapting service facade that translates your service layer's exceptions into UI-specific error states.

Juergen

关于java - UnexpectedRollbackException - 完整的场景分析,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2007097/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com