実際には、レガシー ATG コミュニティでずっと前に推奨されていたベスト プラクティス アプローチがあります。ここに貼り付けるだけです。
同期とトランザクションで Order オブジェクトを使用している場合、従わなければならない特定の使用パターンがあります。予想されるパターンに従わないと、不要な ConcurrentUpdateExceptions、InvalidVersionExceptions、およびデッドロックが発生する可能性があります。コードでは、次の順序に厳密に従う必要があります。
- プロファイル ID のローカル ロックを取得します。
- 取引開始
- 注文時に同期
- 注文オブジェクトに対してすべての変更を実行します。
- OrderManager.updateOrder を呼び出します。
- 同期の終了
- トランザクションを終了します。
- プロファイル ID のローカル ロックを解除します。
手順 1、2、7、8 は、順序の更新が予想される ATG フォーム ハンドラーの beforeSet() および afterSet() メソッドで実行されます。これらには、 PurchaseProcessFormHandler および OrderModifierFormHandler (非推奨) を拡張するフォーム ハンドラーが含まれます。コードが PurchaseProcessFormHandler の外部で注文にアクセス/変更する場合、ローカル ロックを手動で取得する必要がある可能性があります。ロックのフェッチは、TransactionLockService を使用して実行できます。
したがって、 PurchaseProcessFormHandler に基づいて ATG フォーム ハンドラーを拡張し、注文を更新する handleXXX() メソッドにカスタム コードを記述した場合、コードは次のようになります。
synchronized( order )
{
// Do order updates
orderManager.updateOrder( order );
}
PurchaseProcessFormHandler の外部で注文を更新するカスタム コードを記述した場合 (例: CouponFormHandler、ドロップレット、パイプライン サーブレット、フルフィルメント関連)、コードは次のようになります。
ClientLockManager lockManager = getLocalLockManager(); // Should be configured as /atg/commerce/order/LocalLockManager
boolean acquireLock = false;
try
{
acquireLock = !lockManager.hasWriteLock( profileId, Thread.currentThread() );
if ( acquireLock )
lockManager.acquireWriteLock( profileId, Thread.currentThread() );
TransactionDemarcation td = new TransactionDemarcation();
td.begin( transactionManager );
boolean shouldRollback = false;
try
{
synchronized( order )
{
// do order updates
orderManager.updateOrder( order );
}
}
catch ( ... e )
{
shouldRollback = true;
throw e;
}
finally
{
try
{
td.end( shouldRollback );
}
catch ( Throwable th )
{
logError( th );
}
}
}
finally
{
try
{
if ( acquireLock )
lockManager.releaseWriteLock( profileId, Thread.currentThread(), true );
}
catch( Throwable th )
{
logError( th );
}
}
このパターンは、複数のスレッドが同じATG インスタンスで同じ順序を更新しようとしたときに、ConcurrentUpdateExceptions、InvalidVersionExceptions、およびデッドロックを防ぐためにのみ役立ちます。これは、コマース サイトのほとんどの状況に適しているはずです。これは、セッション スティッキネスによって、同じ順序への更新が同じ ATG インスタンスに限定されるためです。