1

メッセージを処理するための MDB と一連のステートレス EJB があります (WAS 7.0、Java EE 5、EJB 3.0、JPA)。

シーケンス (CMT を使用):

  • MDB はメッセージを受け入れます
  • MDB は、メッセージの詳細を含むエンティティを永続化します
  • MDB は EJB 1 を呼び出し、エンティティ ID を渡します。
  • EJB1 は、呼び出しが成功したかどうかに応じて、メッセージを処理します。
  • ID を渡す EJB2 または EJB5
  • EJB2 は...

というように、最後の EJB まで実行されます (実行時間は数分です)。

これらはすべて 1 つのトランザクションで発生します。したがって、EJB4 で何かがスローされた場合、このトランザクションで以前に発生したすべてがロールバックされます。後続のすべての呼び出しに REQUIRES_NEW を使用しようとしましたが、以前の呼び出しの変更は後続の呼び出しには表示されないようです。また、トランザクションが長くなり、タイムアウトすることもあります。

次の項目について、個別の独立した取引を行いたいと考えています。

  • 受信し持続するメッセージ
  • EJB1でのB処理
  • EJB2 での C 処理

.... したがって、EJB2 の実行が失敗した場合、メッセージは DB に残り、EJB1 での実行結果も永続化されます。

主な質問は、CMT を使用することです。一連の短い独立したトランザクションを持つことは可能ですか?

もう少し

  • MDB で開始されたトランザクションは、EJB1 への呼び出しの結果とは無関係にコミットできますか? さらに -- EJB1 への呼び出しの前にコミット..?
  • MDB 内で行われたエンティティの変更は、REQUIRES_NEW 属性を持つ EJB1 メソッドへの呼び出し内で表示できますか?
  • BTMまたはWorkManager以外に目標を達成する方法はありますか?
4

1 に答える 1

1

REQUIRES_NEW に問題はないはずです。

あなたがこれを持っていたら:

@EJB(..)
EJB1 ejb1;
@EJB(..)
EJB2 ejb2;

public void onMessage(Message message) {
    Thing thing = getThingFromMessage(message);

    persistThingStuff(thing);
    ejb1.doThingStuffWithRequiresNew(thing);
    ejb2.doThingStuffWithRequiresNew(thing);
}

それは1つの注意点でうまくいくはずです。

ejb2 が例外をスローすると、ejb1 の作業はコミットされますが、persistThingStuff はロールバックします。

しかし、次のようなことをすると:

public void onMessage(Message message) {
    Thing thing = getThingFromMessage(message);

    persistThingStuff(thing);
    ejb1.doThingStuffWithRequiresNew(thing);
    try {
        ejb2.doThingStuffWithRequiresNew(thing);
    } catch (Throwable t) {
        youBetterLogThis();
    }
}

これにより、例外によって MDB の作業が吹き飛ばされるのを防ぐことができますが、EJB2 が長時間実行されている場合、MDB によって行われた作業は保留中であり、開いているトランザクションで待機しています。

これらの多くを回避するために、ユーティリティ EJB 関数があります。

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public <T extends Runnable> T runInTransaction(T runner) {
    runner.run();
    return runner;
}

そのため、必ずしも特定のメソッドに注釈を付ける必要はありません。

@EJB(...)
UtilEJB utilEjb;

public void onMessage(Message message) {
    final Thing thing = getThingFromMessage(message);

    utilEjb.runInTransaction(new Runnable() {
        public void run() {
            persistThingStuff(thing);
        }
    });
    ejb1.doThingStuffWithRequiresNew(thing);
    try {
        ejb2.doThingStuffWithRequiresNew(thing);
    } catch (Throwable t) {
        youBetterLogThis();
    }
}

これにより、EJB1 の前であっても、MDB 作業がすぐにコミットされます。

于 2013-01-16T01:26:14.050 に答える