-1

私は、一連の操作を単一のトランザクションにまとめ、MDBからスレッドセーフである必要がある状況があります。メッセージ駆動型Beanの並行処理 - スレッドセーフJava EE5とEE6

スレッドAが命令1を実行する場合、スレッドAが処理しているデータは他のスレッドが少なくとも同じではないことを読み取らないようにします。 IMAGEテーブルには異なるソースからの重複データが含まれているため、以下のコードでは、これは重複したINFRANCTIONにつながります。避けなければならない状況。

私が見つけた実際の解決策は、新しいメッセージごとに新しいトランザクションを宣言し、トランザクション全体を同期させることです。 はコードの簡素化:

@Stateless 
InfranctionBean{ 
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) 
    checkInfranction(String plate){ 
     1. imageBean.getImage(plate); // read from table IMAGE 
     2. infranctionBean.insertInfranction(String plate); // insert into table INFRANCTION 
     3. imageBean.deleteImage(String plate); //delete from table IMAGE 
    } 
} 

@MessageDriven 
public class ImageReceiver { 

    private static Object lock = new Object(); 

    public void onMessage(Message msg){ 
     String plate = msg.plate; 

     synchronized (lock) { 
      infanctionBean.checkInfranction(plate); 
     } 
    } 
} 

私はEJB内のsynchronizedブロックを使用すると、EJB仕様によってrecommandedされていないことを認識しています。これは、アプリケーションサーバが2つのノードクラスタで動作する場合でも問題が発生する可能性があります。

EE6のように、このシナリオの解決策、つまりEJB Singletonが導入されているようです。コンテナは、同時実行を処理するため、

@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER) 
@Singleton 
InfranctionBean{ 

    @Lock(LockType.WRITE) 
    checkInfranction(String plate){ 
     1... 
     2... 
     3... 
    } 
} 

そしてMDBからの同期ブロックの使用neccessaryではないでしょう。 この場合、私の解決策は、このようなものは次のようになります。 @Lock(WRITE)を使用すると、コンテナはcheckInfranction()内の単一スレッドへのアクセスを保証します。

私のクエストオンは:どのように私はこの状況をEE5で処理できますか?同期ブロックを使用しないでクリーナーソリューションがありますか?

環境:Java5、jboss-4.2.3.GA、Oracle10。 20.000受信メッセージ(同時にそれらの半分)に

実際の解

@Stateless 
InfranctionBean{ 
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) 
    checkInfranction(String plate){  
     1. imageBean.lockImageTable(); // lock table IMAGE in exclusive mode 
     2. imageBean.getImage(plate); // read from table IMAGE 
     3. infranctionBean.insertInfranction(String plate); // insert into table INFRANCTION 
     4. imageBean.deleteImage(String plate); //delete from table IMAGE 
    } 
} 

@MessageDriven 
public class ImageReceiver { 
    public void onMessage(Message msg){ 
     infanctionBean.checkInfranction(msg.plate); 
    } 
} 

アプリケーションがうまく動作ようです。

答えて

1

@Lock(WRITE)は、単一のアプリケーション/ JVM内のロックに過ぎません。したがって、アプリケーション/ JVMが1つしかデータにアクセスしないことを保証できない限り、保護はあまり得られません。単一のアプリケーション/ JVM保護のみを探している場合、EE 5の最良のソリューションはReadWriteLockか、おそらく同期化されたブロックです。 (EJB仕様には、アプリケーションがサーバーのスレッド管理を損なうのを避けるためにアプリケーションを止める言葉があるので、無期限にブロックしないように注意し、割り込みを無視しないように注意してください)

より堅牢なクロスアプリケーション/ JVMソリューションを探しているので、私はJVM同期プリミティブに頼るのではなく、データベースロックまたは分離レベルを使用します。これはおそらく、使用されているEJBのバージョンに関係なく最適なソリューションです。

+0

返信ありがとうございました。データベースロックではどういう意味ですか?あなたは、原子ブロックの第一歩として、 'EXCUSIVE MODEのロックテーブルイメージ 'のようなことをしますか?私の場合はcheckInfranction()メソッド。 – Ermal

+0

私はデータベースの専門家ではありませんが、私は2つの一般的なアプローチを知っています。まず、ロック・オブジェクトの同期と同様のデータベース・ロックを使用できます。また、読み取りコミット、反復可能読み取り、またはシリアライズ可能なような強力な分離レベルを使用することもできます。これにより、基本的に、2つのスレッドがデータの読み取り/更新を行う方法によって暗黙的にロックされ、更新されるデータ別のスレッドの別のトランザクション –

+0

これは私がブレットを必要とするものです。分離レベルSERIALIZABLEなので、checkInfranction()に入力すると、他のスレッドがIMAGEテーブルを読み取ることはできません。私の質問は、将来的な実施からのものでした。とにかくあなたの答えは私に解決策を通らせましたので、私は解答を受け入れるつもりです。ありがとうございました! – Ermal

関連する問題