Hibernate flush和JTAUnexpectedRollbackException

时间:2009-07-23 00:05:42

标签: java database hibernate spring

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

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

2 个答案:

答案 0 :(得分:1)

首先,免责声明:我不使用Atomikos。我不相信它与有问题的错误有任何关系,但肯定不知道。

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

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

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

答案 1 :(得分:1)

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

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

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