如何使用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 并重做那个?
谢谢
I need some clarification on the right way to retry a "retryable" exception (e.g. something like lock wait timeout) when using java persistence. 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. Can I just wrap that in a try/catch and retry it (with some count, obviously)? Or do I have to wrap the whole tx.begin/commit and redo that?
thx
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
假设锁超时不是数据库死锁的解决方法,一个更简单的解决方案是对请求使用更长的超时。不要使用
N
秒超时并重试最多C
次,而是将超时设置为N * (C + 1)
秒。(如果您使用锁定超时作为死锁的解决方法,那么您会遇到更大的问题。您最好尝试修复死锁的根本原因,因为即使使用
C
也会重试是您的交易无法成功的概率。)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 toC
times, set the timeout toN * (C + 1)
seconds.(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.)如果您按照规范进行编程,那么您实际上应该处理整个 EntityManager 并重新开始。不存在保证在 EM 级别“可重试”的例外情况。如果 persist() 方法出现异常,则整个持久会话将被视为不一致/不确定。
有时它会起作用。我知道在休眠状态下,您通常可以在乐观锁异常后尝试获得增益。但一般来说,您依赖于供应商特定的行为,如果您尝试捕获实体管理器异常并从中恢复并保持相同的实体管理器,则这些行为可能定义不明确。
更多信息请参见此处。
If you are programming to the spec, you are actually supposed to dispose the entire EntityManager and start over. There are no exceptions that are guaranteed to be 'retryable' at the EM level. Your entire persistence session is considered inconsistent/indeterminate if an exception comes out of the persist() method.
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.
More info here.
只要 EntityManager 抛出的异常不将事务标记为仅回滚(LockTimeoutException 就是这样的示例,但 PessimisticLockException 不是),您就可以继续处理当前事务中的事务。
如果 TX 被标记为仅回滚,则您必须挽救 TX,然后重试在 TX 内发生错误之前尝试的任何操作并继续。
如果您要使用 JPA 循环处理大量内容,那么您很可能有一个很好的 DELETE 或 UPDATE jpql 查询候选者。
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.
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.
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.