有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

hibernate如何使用java持久性重试锁定等待超时?

我需要澄清一下,在使用java持久性时,如何正确地重试“可重试”异常(例如锁等待超时)。例如,使用伪代码,如:

EntityTransaction tx = em.getTransaction();
tx.begin();
for (a bunch of objects) {
  em.persist(object);
}
tx.commit();

如果数据库中有锁,我有时会在em.persist调用中抛出异常。我能用try/catch把它包装起来,然后再试一次吗(当然,有一些计数)?或者我必须包装整个tx.begin/commit和redo

thx


共 (3) 个答案

  1. # 1 楼答案

    假设锁超时不是数据库死锁的解决方法,一个更简单的解决方案是对请求使用更长的超时时间。不要使用N秒超时并最多重试C次,而是将超时设置为N * (C + 1)

    (如果您使用锁超时作为死锁的解决方法,那么您会遇到更大的问题。您最好尝试修复死锁的根本原因,因为即使重试C,您的事务也有可能无法通过。)

  2. # 2 楼答案

    只要EntityManager引发的异常没有将事务标记为仅回滚(LockTimeoutException就是这样一个例子,但悲观LockException不是),您就可以继续处理当前事务中的内容

    如果TX被标记为仅回滚,则必须退出TX,然后重试TX中发生错误之前尝试的任何操作,然后继续

    如果你正在使用JPA进行大量的循环,那么很可能你有一个很好的删除或更新jpql查询的候选者

  3. # 3 楼答案

    如果您是按照规范编程的,那么实际上应该处理整个EntityManager并重新开始。在EM级别,没有保证“可重试”的例外情况。如果persist()方法出现异常,则整个持久性会话被视为不一致/不确定

    有时它会奏效。我知道在hibernate中,你通常可以在乐观锁异常后尝试增益。但一般来说,如果您试图捕获entitymanager异常并从中恢复,并保留同一个entitymanager,那么您依赖的是特定于供应商的行为,而这些行为可能定义不清

    More info here.