【问题标题】:Hibernate flush and JTAUnexpectedRollbackException休眠刷新和 JTAUnexpectedRollbackException
【发布时间】:2010-11-13 05:24:14
【问题描述】:

我正在使用 Spring 和 Hibernate。和 Atomikos 进行交易。我使用基于注释的事务。我有一个 DAO 对象,并在其中一种方法中调用 entityManager.persist() 来保存对象。 现在,每当更新期间出现 ORA 错误时,例如违反约束或其中一列的长度超过数据库中定义的 wat,我会得到 JTAUnexpectedRollbackException 而不是 Spring 抛出的 GenericJDBCException。 我尝试尝试坚持以抓住这一点,但我没有得到任何异常。似乎 Hibernate 在刷新期间执行了实际的更新语句,这发生在事务提交期间,因此我猜是 UnexpectedRollbackException。

如何解决这个问题并获取 GenericJDBCException 而不是 UnexpectedRollbackException?

【问题讨论】:

  • 为什么获得 GenericJDBCException 而不是 JTAUnexpectedRollbackException 如此重要?为什么要在持久化上捕获异常而不是在事务提交时捕获?
  • 因为当调用我的库的客户端得到 UnexpectedRollback 时他不知道出了什么问题,GenericJDBCException 显示了 SQLException 的堆栈跟踪,但回滚异常没有完整的堆栈跟踪。跨度>
  • 是的,使用 Spring 管理事务的部分优势在于,无论底层如何,都有一个统一的异常。

标签: java database hibernate spring


【解决方案1】:

首先,免责声明:我不使用 Atomikos。我不认为它与所讨论的错误有任何关系,但不能确定。

不久前我在 Spring / Hibernate 应用程序中遇到了一个非常相似的问题。 Hibernate 确实只在刷新期间将会话更新传播到数据库。问题是根据刷新模式,刷新可能在不同的时间发生。它默认为AUTO,这意味着如果会话包含可能影响查询结果的更新,则可能会在查询执行之前发生刷新。你有几个选择:

A) 您可以在调用entityManager.persist() 后立即手动调用entityManager.flush() 并在此时捕获异常(如果有)。这样做的缺点(可能适用于您的情况,也可能不适用)是刷新会中断批量更新,因此如果您在单个事务中为同一实体类型执行多次插入/更新,您可能会遇到(可能)显着的性能下降.

B) 您可以将刷新模式设置为 COMMIT,这将延迟刷新直到事务提交(或直到手动调用 flush())。然后,您可以在此时捕获异常,或者,如果由于 Atomikos 而证明这是不可能的,您可以在提交之前手动调用flush()(例如,在服务调用结束时)。缺点是这比选项 A 更难(在我的情况下更难,Atomikos 可能更难 - 我不知道)并且您的查询可能会返回陈旧的数据。

【讨论】:

    【解决方案2】:

    如果UnexpectedRollbackException 包含GenericJDBCException 作为它的原因或下游的几个原因,您可以使用getCause()getRootCause() 方法以编程方式获取它并重新抛出它。

    try {
        em.flush();
    } catch (UnexpectedRollbackException e) {
        if (e.getRootCause() instanceof GenericJDBCException) {
            throw e.getRootCause();
        }
    }
    

    我不确定 getRootCause() 或 getCause() [.getCause()] 是否返回 GenericJDBCException,您可能应该使用调试器找出它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-29
      • 1970-01-01
      • 2014-02-03
      • 1970-01-01
      • 2012-04-14
      • 1970-01-01
      • 2019-03-26
      • 2012-12-23
      相关资源
      最近更新 更多