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