0

ATG で構築された当社の e コマース アプリケーションには、複数のユーザーが同じ注文を更新できる機能があります。Order のキャッシュ モードがSimple- であるため、多数のConcurrentUpdateExceptionとが発生しましたInvalidVersionException。キャッシュ モードを検討lockedしていましたが、オーダーが非常に頻繁に更新され、ロックによってデッドロックが発生し、パフォーマンスに影響を与える可能性があるため、ロックされたキャッシュの使用には懐疑的です。

シンプル キャッシュ モードを引き続き使用し、ConcurrentUpdateException と InvalidVersionException の発生を最小限に抑える方法はありますか?

4

2 に答える 2

1

実際には、レガシー ATG コミュニティでずっと前に推奨されていたベスト プラクティス アプローチがあります。ここに貼り付けるだけです。

同期とトランザクションで Order オブジェクトを使用している場合、従わなければならない特定の使用パターンがあります。予想されるパターンに従わないと、不要な ConcurrentUpdateExceptions、InvalidVersionExceptions、およびデッドロックが発生する可能性があります。コードでは、次の順序に厳密に従う必要があります。

  1. プロファイル ID のローカル ロックを取得します。
  2. 取引開始
  3. 注文時に同期
  4. 注文オブジェクトに対してすべての変更を実行します。
  5. OrderManager.updateOrder を呼び出します。
  6. 同期の終了
  7. トランザクションを終了します。
  8. プロファイル 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 インスタンスに限定されるためです。

于 2015-08-07T21:51:00.807 に答える