このリトライ問題に既成のものはないと思います。何かをやり直そうとしたり、PersistenceException オブジェクトをキャッチしたりする代わりに、手元にある現在のタスクのより良いパターンもあります。
Spring を使用しているため、トランザクション処理にJava Transaction Service (JTA)を使用するか、JPA 互換モードで Hibernate を使用する可能性が高いです。したがって、セッションの永続コンテキストは、トランザクションのコミット後にクリアされます。これにより、エンティティが現在の (したがって任意の) セッションから切り離されます。
したがって、特定のエンティティに対して行ったすべての変更は、セッションによって管理されなくなります (エンティティがまだセッションによって管理されている場合は、手動でデタッチするために使用できます。Hibernatesession.evict(entity)
のドキュメントで、デタッチされたオブジェクトについて何かを読みたいと思うかもしれません:切り離されたオブジェクト。
を使用するだけで、エンティティが表すデータベース要素の現在の状態を再読み込みできるようになりましたMyEntity currentState = session.get(EntityClass.class, detachedEntity.getId());
。currentState オブジェクトのプロパティを調べることで、バージョン番号を簡単にテストできます。異なる場合は、データベース内の状態が変化しているため、特別な条件をテストしてそれに応じて対処できます。
例:
たとえば、以前に実装したものを使用します。特定のビジネス レポートを担当者に送信する電子メール システムがあります。メールの作成には 5 分以上かかります。メールの作成は、毎日の業務を中断しないように午前 0 時以降に延期されます (これらのレポートを作成するためのデータベースの使用率は膨大です)。
したがって、私たちの(テストされていない、説明のためだけの)コードは次のようになります。
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();
最初に次の電子メール タスクを取得し、電子メールの計算を開始しますが、これには時間がかかります。次に、タスクが変更されていないかどうか、または他のプロセスによって変更されているかどうかを確認します (エラーが発生したため)。その場合、タスクを完了としてマークし、実際にメールを送信します。(データベースを変更した後ではなく、実際にメールを送信する前に、システムがクラッシュしないと想定しています。