使用JPA和Hibernate重试乐观锁定异常

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用JPA和Hibernate重试乐观锁定异常相关的知识,希望对你有一定的参考价值。

我在hibernate中遇到了一些脏写问题。我添加了@version字段,以便我可以看到我是否正在写一个过时的表。这意味着我现在有很多锅炉板代码

try {
   tryWriteToTable();
} catch (PersistenceExcepton) {  //subclasss of OptimisiticLockException
   try {
      tryWriteToTable();
   } catch (PersistenceExcepton) {
       //dont try again - something seriously wrong
   }
}  

我正在使用Spring,并想知道是否有任何东西可以让我定义这个模式。如果有异常,可以让我重复的东西。除了Spring之外,我还可以使用其他任何东西来避免所有这些丑陋的锅炉板代码。

我想要这样的东西

@TryTwice
private void tryWriteToTable() ....

谢谢

答案

我写了一篇关于this topic的帖子,还有一个你可以在Maven Central找到的小GitHub project

它基于Spring AOP,它提供了一个@Retry注释来标记您希望在乐观锁定异常上重试的服务。

另一答案

我认为这个重试问题没有现成的东西。对于当前的任务,还有一个更好的模式,而不是尝试重做某些东西或捕获PersistenceException对象。

由于您使用的是Spring,并且很可能使用Java Transaction Service (JTA)进行事务处理或在JPA兼容模式下使用Hibernate。因此,会话的持久化上下文将在事务提交后清除。这使您的实体与当前(因此任何)会话分离。

因此,您为给定实体所做的每个更改都不再由会话管理(如果您的实体仍由会话管理,您可以使用session.evict(entity)手动分离它。您可能希望在Hibernate文档中阅读有关分离对象的内容:Working with detached objects

现在,您只需使用MyEntity currentState = session.get(EntityClass.class, detachedEntity.getId());即可重新加载实体所代表的数据库元素的当前状态。通过检查currentState对象的属性,您可以轻松地测试版本号。如果它不同,则数据库中的状态已更改,您可以测试特殊条件并采取相应措施。

例:

例如,我们使用了一段时间以前实现的东西。我们有一个电子邮件系统向负责人发送某些业务报告。要创建电子邮件,需要5分钟或更长时间。午夜后创建电子邮件会延迟,以免中断日常操作(创建这些报告的数据库利用率很高)

所以我们(未经测试,仅用于说明)代码如下所示:

session.beginTransaction();
EmailTask task = getRandomNextTask(session);
session.getTransaction().commit(); //end transaction, task is detached

prepareEmail(); //takes 5minutes or more

session.beginTransaction();
EmailTask currentState = session.get(EmailTask.class, task.getId());
if(currentState.getVersion() == task.getVersion() || currentState.hasError()) {
     currentState.markDone();
     session.getTransaction().commit();
     sendEmail();
} 
else
    trashEmail();

因此,您可以看到我们首先获得下一个电子邮件任务并开始计算需要一些时间的电子邮件。然后我们检查任务是否未被更改,或者如果某个其他进程已更改它,我们检查该进程是否实际上没有发送电子邮件(因为它导致了错误)。如果是这样,我们将任务标记为已完成并实际发送电子邮件。 (我们假设我们的系统在更改数据库之后但在实际发送电子邮件之前不会崩溃。

以上是关于使用JPA和Hibernate重试乐观锁定异常的主要内容,如果未能解决你的问题,请参考以下文章

使用 JPA / Hibernate 在无状态应用程序中进行乐观锁定

如何处理锁(JPA)?

JPA 和乐观锁定模式

乐观锁定的 JPA 版本字段的最佳类型

休眠乐观锁定..它是如何工作的?

JPA 在带有 DTO 和乐观锁定的 RESTful Web 应用程序中合并?