私はSpring2.5とHibernateJPAの実装をJavaと「コンテナー」管理トランザクションで使用しています。
バックグラウンドでデータを更新する「ユーザーコミット後」メソッドがあり、クライアントに表示されることはないため、例外にConcurrencyFailureException
関係なくコミットする必要があります。StaleObjectStateException
言い換えれば、楽観的なロックを悲観的にする必要があります。(メソッドの実行に少し時間がかかり、誰かが他のトランザクションでデータを変更した場合に発生する可能性があります)
べき等について多くのことを読みました。DEFAULT_MAX_RETRIESまたは6.2.7の検索で例外が発生した場合は、再試行してください。例または第14.5章。再試行します。私はこことここのstackoverflowでも見つけました。
私はこれを試しました:
public aspect RetryOnConcurrencyExceptionAspect {
private static final int DEFAULT_MAX_RETRIES = 20;
private int maxRetries = DEFAULT_MAX_RETRIES;
Object around(): execution( * * (..) ) && @annotation(RetryOnConcurrencyException) && @annotation(Transactional) {
int numAttempts = 0;
RuntimeException failureException = null;
do {
numAttempts++;
try {
return proceed();
}
catch( OptimisticLockingFailureException ex ) {
failureException = ex;
}
catch(ConcurrencyFailureException ex) {
failureException = ex;
}
catch( StaleObjectStateException ex) {
failureException = ex;
}
} while( numAttempts <= this.maxRetries );
throw failureException;
}
}
RetryOnConcurrencyException
例外が発生した場合に再試行する必要があるメソッドをマークするためのアノテーションです。動作しませんでした...私もいくつかの方法を試しましたSELECT ... FOR UPDATE
、EntityManager.lock(...)
Springでこのような戦略を使用して、古いデータやダーティリードなどを回避するための最良の方法は何ですか?再試行?、同期?、JPAロック?、分離?、更新のために...を選択しますか?私はそれを機能させることができませんでした、そして私はどんな助けにも本当に満足しています。
これが私がやりたい擬似コードです:
void doSomething(itemId) {
select something into A;
select anotherthing into B;
// XXX
item = getItemFormDB( itemId ); // takes long for one user and for other concurrent user it could take less time
item.setA(A);
item.setB(B);
// YYYY
update item;
}
//XXXと//YYYの間で、別のセッションがアイテムを変更する可能性があり、StaleObjectStateExceptionがスローされます。