简体   繁体   English

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

[英]How to retry a lock wait timeout using java persistence?

I need some clarification on the right way to retry a "retryable" exception (eg something like lock wait timeout) when using java persistence. 我需要对使用Java持久性时重试“可重试”异常(例如类似锁等待超时之类)的正确方法进行一些说明。 For example, with pseudocode like: 例如,使用伪代码,例如:

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

I sometimes get an exception thrown at the em.persist call if there's a lock in the db. 如果数据库中有锁,有时会在em.persist调用中引发异常。 Can I just wrap that in a try/catch and retry it (with some count, obviously)? 我可以将其包装在try / catch中然后重试吗(很明显,有一些计数)? Or do I have to wrap the whole tx.begin/commit and redo that ? 还是我必须包装整个tx.begin / commit并重

thx 谢谢

Assuming that the lock timeouts are not there as a workaround for database deadlocks, a simpler solution would be to just use longer time-outs on your requests. 假设没有锁定超时作为解决数据库死锁的方法,那么一个更简单的解决方案是对请求使用更长的超时。 Instead of using an N second timeout and retrying up to C times, set the timeout to N * (C + 1) seconds. 将超时设置为N * (C + 1)秒,而不是使用N秒的超时并重试最多C次。

(If you are using the lock timeouts as a workaround for deadlocks, then you have a bigger problem. You'd do better to try to fix the root cause of the deadlocks, because even with C retries there is a probability that your transactions won't go through.) (如果您将锁定超时用作死锁的一种解决方法,那么您会遇到更大的问题。您最好尝试解决死锁的根本原因,因为即使使用C重试,您的交易也有可能获胜不能通过。)

So long as the exception thrown by the EntityManager does not mark the transaction as rollback only (LockTimeoutException is one such example, however PessimisticLockException is not) you can continue to process things in the current transaction. 只要EntityManager抛出的异常不会将事务标记为仅回滚(LockTimeoutException是此类示例之一,而PessimisticLockException并非如此),则可以继续处理当前事务中的事务。

If the TX gets marked as rollback only, you'll have to bail out the TX, then retry anything that you attempted -before- the error occurred within the TX and continue along. 如果TX仅被标记为回滚,则您必须对TX进行保释,然后重试TX内发生错误之前的任何尝试,然后继续操作。

If you're going gobs of things in a loop with JPA, chances are you have a good candidate for a DELETE or UPDATE jpql query. 如果要通过JPA循环进行工作,那么您很有可能是DELETE或UPDATE jpql查询的候选人。

If you are programming to the spec, you are actually supposed to dispose the entire EntityManager and start over. 如果您按照规范进行编程,则实际上应该处置整个EntityManager并重新开始。 There are no exceptions that are guaranteed to be 'retryable' at the EM level. 没有任何例外可以保证在EM级别“可重试”。 Your entire persistence session is considered inconsistent/indeterminate if an exception comes out of the persist() method. 如果persist()方法产生异常,则整个持久性会话将被视为不一致/不确定。

Sometimes it will work. 有时它将起作用。 I know in hibernate you can usually get away with trying gain after an optimistic lock exception. 我知道在休眠状态下,您通常可以在乐观锁定异常之后尝试获得收益。 But in general, you are relying on vendor specific behavior that may be poorly defined if you try to catch and recover from entitymanager exceptions and keep the same entitymanager. 但是总的来说,如果您试图捕获并从entitymanager异常中恢复并保持相同的entitymanager,则您将依赖于供应商特定的行为,这些行为可能定义不清。

More info here. 更多信息在这里。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM