JPA:处理 OptimisticLockException 的模式
Posted
技术标签:
【中文标题】JPA:处理 OptimisticLockException 的模式【英文标题】:JPA: pattern for handling OptimisticLockException 【发布时间】:2011-09-26 08:45:11 【问题描述】:在 (REST) Web 服务中处理 OLE 的正确模式是什么?这就是我现在正在做的,例如,
protected void doDelete(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
...
...
...
try
try
em.getTransaction().begin();
// ... remove the entity
em.getTransaction().commit();
catch (RollbackException e)
if (e.getCause() instanceof OptimisticLockException)
try
CLog.e("optimistic lock exception, waiting to retry ...");
Thread.sleep(1000);
catch (InterruptedException ex)
doDelete(request, response);
return;
// ... write response
catch (NoResultException e)
response.sendError(HttpServletResponse.SC_NOT_FOUND, e.getMessage());
return;
finally
em.close();
每当您在代码中看到休眠时,很有可能它是不正确的。有没有更好的方法来处理这个问题?
另一种方法是立即将故障发送回客户端,但我不想让他们担心。正确的做法似乎是尽一切努力使请求在服务器上成功,即使需要一段时间。
【问题讨论】:
【参考方案1】:如果您收到乐观锁定异常,则表示其他事务已提交 更改您尝试更新/删除的实体。由于其他事务已提交,因此立即重试可能会有很大的成功机会。
我也会让方法在 N 次尝试后失败,而不是等待 ***Exception 发生。
【讨论】:
谢谢,这就是我最终实现的。就我而言,第二次尝试成功的机会很大。话虽如此,我承认按照 Augusto 的建议,正确的做法是让客户重试。 获得 OLE 的另一个原因是实体 version 与数据库中的实体不同。它发生在更新操作和一段时间后重试无济于事。另请注意,您要更新的实体必须具有版本的 getter 和 setter 方法。这听起来合乎逻辑,但例如,我正在做某种类型的通用存储库来处理基本的 CRUD 操作,而 JPA 无法访问版本的设置器,在下次更新时提供 OLE。 只是“立即重试”根本不是一个好主意。发生此异常是因为 2 个用户同时编辑同一条信息。一个会成功,而另一个会简单地覆盖第一个所做的。乐观锁定将通过在第二次提交时抛出异常来避免这种情况。这需要用户首先进行干预,以确保两个版本的输入得到验证并以一种或另一种方式合并。 自动重试OptimisticLockException
上的操作不是一个好主意,因为这样可能会丢失重要的更新。【参考方案2】:
“政治上正确”的答案是返回一个 HTTP 409(冲突),这与乐观锁定的想法完美匹配。您的客户应该管理它,可能在几秒钟后重试。
我不会在您的应用中添加重试逻辑,因为当您返回 40X 代码时,您的客户端已经处理了各种情况。
【讨论】:
如果你在一个独立的应用程序中,这不是一个有用的回报。仅当您碰巧处于面向 Web 的环境中时,它才有意义。【参考方案3】:顺便说一句,catch (InterruptedException e)
总是一个坏主意,因为系统已要求您取消计算,而您忽略了它。在 Web 服务的上下文中,InterruptedException
将是向客户端发出错误信号的另一个很好的理由。
【讨论】:
实际上,无论他是否记录异常,系统都在强制代码停止。异常被捕获后,执行不会返回到try块。 虽然这是真的,但它并不能回答问题。我还想补充一点,捕捉异常很好。但是,您应该调用Thread.currentThread.interrupt()
,因为线程的中断状态已被异常清除。【参考方案4】:
如果您只是要继续重试直到它正常工作,为什么不禁用乐观锁定?您应该让来电者知道他们是根据过时的信息做出的决定!如果您控制双方,则可以返回适当的 400 代码。如果它是公开的,那么对任意客户端只返回 500 会更友好。(当然,你会继续使用适当的响应代码!这样的困境)
【讨论】:
如果我没有锁定,我会从数据库中得到死锁异常。以上是关于JPA:处理 OptimisticLockException 的模式的主要内容,如果未能解决你的问题,请参考以下文章
处理 JPA 规范和 spring-data-jpa 时如何使用声明 Stream 作为返回类型
Spring Boot Jpa 批处理-CannotCreateTransactionException