我不认为有什么现成的东西可以解决这个重试问题。对于您手头的当前任务,还有一个更好的模式,而不是尝试重做某事或捕获 PersistenceException 对象。
由于您使用的是 Spring,并且很可能使用Java Transaction Service (JTA)进行事务处理或在 JPA 兼容模式下使用 Hibernate。因此,会话的持久性上下文将在事务提交后被清除。这使您的实体与当前(以及任何)会话分离。
因此,您对给定实体所做的每项更改都不再由会话管理(如果您的实体仍由会话管理,您可以使用session.evict(entity)
它手动分离它。您可能想在 Hibernate 文档中阅读有关分离对象的内容:Working with分离的物体。
现在您可以重新加载实体所代表的数据库元素的当前状态,只需使用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();
所以你可以看到我们首先得到下一个电子邮件任务并开始计算需要一些时间的电子邮件。然后我们检查任务是否没有改变,或者其他进程是否改变了它,我们检查进程是否真的没有发送电子邮件(因为它导致了错误)。如果是这样,我们将任务标记为已完成并实际发送电子邮件。(我们只是假设我们的系统在更改数据库后但在实际发送电子邮件之前不会崩溃。