3

Seam & Hibernate(JDBCからSQLServer)で動作するSeam Webアプリケーションがあります。SeamとHibernateでトランザクションを再試行する最良の方法

これはうまくいきますが、重い負荷(JMeterのストレステスト)の下では、LockAcquisitionExceptionまたはOptimisticLockExceptionがあります。

LockAquisitionExceptionSQLServerExceptionによって引き起こされる「別のプロセスでロックリソースにデッドロックし、デッドロックの対象として選択されたトランザクション(プロセスID 64)。再実行トランザクション

私はその後LockAquisitionExceptionのために、このようなトランザクションを再実行するようSeamインターセプタを書いた:

@AroundInvoke 
public Object aroundInvoke(final InvocationContext invocationContext) throws Exception { 
    if (instanceThreadLocal.get() == null && isMethodInterceptable(invocationContext)) { 
     try { 
      instanceThreadLocal.set(this); 

      int i = 0; 
      PersistenceException exception = null; 
      do { 
       try { 
        return invocationContext.proceed(); 
       } catch (final PersistenceException e) { 
        final Throwable cause = e.getCause(); 
        if (!(cause instanceof LockAcquisitionException)) { 
         throw e; 
        } 
        exception = e; 
        i++; 
        if (i < MAX_RETRIES_LOCK_ACQUISITION) { 
         log.info("Swallowing a LockAcquisitionException - #0/#1", i, MAX_RETRIES_LOCK_ACQUISITION); 
         try { 
          if (Transaction.instance().isRolledBackOrMarkedRollback()) { 
           Transaction.instance().rollback(); 
          } 
          Transaction.instance().begin(); 
         } catch (final Exception e2) { 
          throw new IllegalStateException("Exception while rollback the current transaction, and begining a new one.", e2); 
         } 
         Thread.sleep(1000); 
        } else { 
         log.info("Can't swallow any more LockAcquisitionException (#0/#1), will throw it.", i, MAX_RETRIES_LOCK_ACQUISITION); 
         throw e; 
        } 
       } 
      } while (i < MAX_RETRIES_LOCK_ACQUISITION); 

      throw exception; 

     } finally { 
      instanceThreadLocal.remove(); 
     } 
    } 
    return invocationContext.proceed(); 
} 

最初の質問:はこのインターセプタが正しく仕事をするあなたと思いますか?周りとグーグルによって

Alfrescowith a forum talk here)、 BonitaOrchestraがあまりにも、このようなトランザクションを再実行するためにいくつかのメソッドを持っていることを見て、彼らは、例えば StaleObjectStateException(私の OptimisticLockExceptionの原因)のように、より多くの例外をキャッチしています。

私の第二の質問は、次のとおりです。それは問題だとしてStaleObjectStateExceptionは「行が更新または削除別のトランザクションによって(または保存されていないと値のマッピングが間違ってあった)」)のために、normalyあなただけ、トランザクションを再実行することはできませんデータベースとの同期と@Versionフィールドではありませんか? Alfrescoがそのような例外によって引き起こされたトランザクションを再実行しようとする理由は何ですか?

EDIT:SQLServerExceptionによって引き起こさLockAcquisitionExceptionについては 、私はウェブ上でいくつかのいくつかのリソースを見てきた、と私は私のコードを再確認した場合でも、それはとにかく起こったことを思わ...ここのリンクは以下のとおりです。

でもMicrosoftはデッドロックを最小限に抑えることができますが」は、彼らは完全に回避することができないと言います。フロントエンド・アプリケーションは、デッドロックを処理するように設計されなければならない理由がある。トランザクション(プロセスID 64)のロックリソースを別のプロセスがデッドロックしたと選択されている「

答えて

2

実は私は最終的に有名なをかわす方法を見つけます」デッドロックの犠牲者として。取引を再開してください。

私は本当に質問に答えませんが、私が見たものと私がそれをどうやって管理するかを説明します。

最初は、行ロックをページロックに変換し、デッドロックを生成する「ロックエスカレーションの問題」があると考えました(JMeterテストは、行の選択中に削除/更新するシナリオで実行されますが、削除と更新は必ずしも選択と同じ行に関係しません)。

だから私はLock Escalation in SQL2005How to resolve blocking problems that are caused by lock escalation in SQL Server(MSによる)と最後にDiagnose SQL Server performance issues using sp_lockと読む。

しかし、私がロックエスカレーションの状況にあったかどうかを検出する前に、私はそのページに入ります:http://community.jboss.org/message/95300。 「トランザクションアイソレーション」と、SQLServerには「スナップショットアイソレーション」と呼ばれる特殊なものがあります。

次に、Using Snapshot Isolation with SQL Server and Hibernateを見つけ、Using Snapshot Isolation(MSによる)を読み取った。

だから私が最初に私のデータベースの「スナップショット分離モード」を有効に:

ALTER DATABASE [MY_DATABASE] 
SET ALLOW_SNAPSHOT_ISOLATION ON 

ALTER DATABASE [MY_DATABASE] 
SET READ_COMMITTED_SNAPSHOT ON 

は、その後、私は4096にJDBCドライバのトランザクション分離を定義する必要がありました...そして、本を読むことで、「アクションで休止状態」

Hibernateは、管理対象環境のアプリケーションサーバーによって提供されるデータソースから取得された接続の分離レベルを決して変更しないことに注意してください。 アプリケーションサーバーの設定を使用して、デフォルトの分離を変更することができます。

だから私はConfiguring JDBC DataSources (for JBoss 4)を読み、最後にこれを追加するために、私のdatabase-ds.xmlファイルを編集した:

<local-tx-datasource> 
    <jndi-name>myDatasource</jndi-name> 
    <connection-url>jdbc:sqlserver://BDDSERVER\SQL2008;databaseName=DATABASE</connection-url> 
    <driver-class>com.microsoft.sqlserver.jdbc.SQLServerDriver</driver-class> 
    <user-name>user</user-name> 
    <password>password</password> 
    <min-pool-size>2</min-pool-size> 
    <max-pool-size>400</max-pool-size> 
    <blocking-timeout-millis>60000</blocking-timeout-millis> 
    <background-validation>true</background-validation> 
    <background-validation-minutes>2</background-validation-minutes> 
    <idle-timeout-minutes>15</idle-timeout-minutes> 
    <check-valid-connection-sql>SELECT 1</check-valid-connection-sql> 
    <prefill>true</prefill> 
    <prepared-statement-cache-size>75</prepared-statement-cache-size> 
    <transaction-isolation>4096</transaction-isolation> 
</local-tx-datasource> 

最も重要な部分はもちろん<transaction-isolation>4096</transaction-isolation>です。

そして、私はもはやデッドロックの問題はもうありません! ...私の質問は、今では私のために多かれ少なかれ無駄です...しかし、おそらく誰かが本当の答えを持つことができます!

関連する問題