【问题标题】:UnexpectedRollbackException - a full scenario analysisUnexpectedRollbackException - 完整的场景分析
【发布时间】:2011-01-01 16:50:03
【问题描述】:

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

来自 Spring 的文档:

当尝试提交事务导致意外回滚时抛出

我想一劳永逸地理解

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

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

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

【问题讨论】:

  • 该特定异常仅在某些特定情况下从 Spring TX 基础架构中引发。 UnexpectedRollbackException 中包含什么消息?这将有助于我们追踪它。

标签: java hibernate spring exception


【解决方案1】:

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

我想我们需要区分 在“逻辑”事务范围之间 和这里的“物理”交易......

PROPAGATION_REQUIRED 创建的是 每个的逻辑事务范围 它被应用到的方法。每个 这样的逻辑事务范围可以 单独决定仅回滚 状态,带有外部事务 范围在逻辑上独立于 内部事务范围。的 当然,在标准的情况下 PROPAGATION_REQUIRED 行为,他们 将映射到相同的物理 交易。所以只有回滚标记 在内部事务范围内设置 确实会影响外部交易的 真正承诺的机会。然而, 因为外部事务范围确实 不决定回滚本身, 回滚(由 内部事务范围)来 在那个级别上出乎意料 - 这是 为什么会出现 UnexpectedRollbackException 被抛出。

PROPAGATION_REQUIRES_NEW,相比之下, 使用完全独立的 每个受影响的交易 交易范围。在这种情况下, 基础实物交易将 不同,因此可以提交或 独立回滚,带有外部 交易不受内部影响 事务的回滚状态。

PROPAGATION_NESTED 又不同了 因为它使用单一的物理 具有多个保存点的事务 它可以回滚到。这种偏 回滚允许内部事务 触发其回滚的范围 范围,与外部事务 能够继续身体 尽管进行了一些操作,但仍进行交易 已被回滚。这是 通常映射到 JDBC 保存点, 所以只适用于 JDBC 资源 交易(春天的 数据源事务管理器)。

要完成讨论: UnexpectedRollbackException 也可能 在没有应用程序的情况下被抛出 设置了仅回滚标记 本身。相反,交易 基础设施可能已经决定 唯一可能的结果是 回滚,由于在 当前交易状态。这是 与 XA 特别相关 交易。

正如我上面建议的,抛出一个 内部事务异常 范围,然后在 外部范围和翻译它 进入无声的 setRollbackOnly 调用 应该适用于您的场景。一种 外部事务的调用者将 永远不会看到异常。自从你 只担心这种无声的回滚 因为特殊要求 由来电者强加,我什至会 认为正确的架构 解决方案是在 服务层,并进行翻译 那些异常进入静默回滚 在服务立面层(右 在回到那个特别的地方之前 来电者)。

因为你的问题可能不是 仅关于回滚异常,但 而不是关于抛出的任何异常 从您的服务层,您可以 甚至使用标准的异常驱动 一路回滚 服务层,然后catch和log 此类异常一旦交易 已经完成,在一些 调整服务外观 翻译您的服务层的 UI 特定错误的异常 州。

于尔根

【讨论】:

    【解决方案2】:

    在日志中向后滚动一点(或增加它的缓冲区大小),您将看到究竟是什么导致了异常。

    如果碰巧不存在,请检查UnexpectedRollbackExceptiongetMostSpecificCause()getRootCause() 方法——它们可能有用。

    【讨论】:

    • 如果日志(缓冲区大小增加)包含确切原因,我就不会在这里问了。我想了解引发此异常的场景。为什么我的设置相关?顺便说一下HibernateTransactionManager的一个很常见的Hibernate + Spring配置
    • 跳过事务回滚的根本原因是一个常见的错误,因为它在stacktrace中非常落后,并且有时会在其间输出sql查询。我要求您进行设置,否则我(或其他任何人)无法猜测实际可能导致此问题的原因。无论如何,请查看我更新的答案以获取另一个提示。
    • @Bozho - +1 用于更新,但要接受答案,我想了解回滚是发生在数据库中还是在服务器中(例如在软件事务管理器中或在数据库中通过JDBC 异常)也许我没有问正确的问题?
    • 好吧,最终,通过调用 getRootCause() 和 getCause()(以不为 null 的为准),您可以获得真正的根异常,它会告诉您您想要的详细信息(希望如此)。跨度>
    • 只是实时使用,确实在日志中向上滚动就可以了 :)
    【解决方案3】:

    我可以告诉你如何重现 UnexpectedRollbackException。我正在研究我的项目,在以下情况下我得到了这个 UnexpectedRollbackException。我的项目中有控制器、服务和 dao 层。 我所做的是在我的服务层类中,

    class SomeServiceClass {
        void outerTransaction() {
            // some lines of code
            innerTransaction();
            //AbstractPlatformTransactionManager tries to commit but UnexpectedRollbackException is thrown, not here but in controller layer class that uses SomeServiceClass.
        }
    
        void innerTransaction() {
            try {
                // someDaoMethod or someDaoOperation that throws exception
            } catch(Exception e) {
                // when exception is caught, transaction is rolled back, outer transaction does not know about it.
                // I got this point where inner transaction gets rolled back when I set HibernateTransactionManager.setFailEarlyOnGlobalRollbackOnly(true)
                // FYI : use of following second dao access is wrong, 
                try {
                    // again some dao operation
                } catch(Exception e1) {
                    throw e2;
                }
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2014-01-22
      • 2014-08-12
      • 2012-08-28
      • 1970-01-01
      • 2011-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多