1

TemporaryQueue を介して別のモジュールの MDB とメッセージを同期的に交換する必要がある EJB モジュールがあります。EJB コンテナー (私の場合は Glassfish 4.0) はトランザクション環境を前提としています。BEAN 管理のトランザクションを使用し、UserTransaction オブジェクトを使用してトランザクションの開始と終了を示す必要がありますか。

私のコードの概要は次のとおりです。

@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class CommunicationJMSUtils {
    @Resource
    private UserTransaction ut;
    @Inject
    private JMSContext context;
    @Resource(lookup = "jms/DestinationQueue")
    private Queue destination;
    private static final long JMS_COMMUNICATION_TIMEOUT = 5000;

    public Map<String, String> getClientordersData(String id) throws JMSException {

    try {
            MapMessage mm = context.createMapMessage();
            ut.begin();
            TemporaryQueue replyQueue = context.createTemporaryQueue();

            mm.setJMSReplyTo(replyQueue);

            mm.setStringProperty(<...>);
            <...>   
            mm.setString(<...>);
            <...>

            context.createProducer().send(destination, mm);
            ut.commit();

            ut.begin();
            ObjectMessage om = (ObjectMessage) context.createConsumer(replyQueue).receive(JMS_COMMUNICATION_TIMEOUT);
            ut.commit();

            if (om != null) {
                return om.getBody(Map.class);
            } else {
                throw new JMSException("Failed to receive reply within " + JMS_COMMUNICATION_TIMEOUT);
            }
        } catch (NotSupportedException | RollbackException | HeuristicMixedException | HeuristicRollbackException | SecurityException | IllegalStateException | SystemException ex) {
        <...>
        }
    }
}

最初の問題は、時々、このコード (受信部分) が例外で失敗することです。

    MQJMSRA_DS4001: _checkDestination:Temporary Destination not owned by  parent connectionId=1760697170479431168

明らかに、TemporaryQueue は同じ JMSContext で作成されます。

そして 2 つ目の問題は、このコードの「脆弱性」です。context.createMapMessage() を最初のトランザクション内に配置するか、TemporaryQueue の作成を最初のトランザクションの外に移動すると、このスニペットは間違いなく失敗します。

残念ながら、JMS のチュートリアルやドキュメントは、その特定のユース ケースを実際にはカバーしていません。Java EE で JMS 2.0 を使用して JMS 要求/応答パターンを実装する正しい方法は何ですか?

4

1 に答える 1

1
  • メッセージングは​​本質的に非同期であるため、JMS を使用した同期動作と (非同期) メッセージングは​​何らかの形で競合します。JMS を使用する代わりに、たとえばローカルまたはリモート EJB でメソッドを呼び出すだけです。ステートレス セッション Bean と MDB は同じ機能 (サービス クラス) を呼び出すことができますが、この方法では 2 つの異なるタイプのインターフェイス (同期と非同期) を提供します。 )。

  • メソッドを呼び出すための一時的なキューを作成することさえありますが、これは複雑さを増します (そしてこれが問題を引き起こしています)。

  • UserTransactionすべての操作にまたがる必要があります。begin, and commit(and )は 1 つだけである必要がありますrollback。実際のトランザクション境界が見えません。最初の TX のリソースが 2 番目の TX で使用されています ( replyQueue)。最初のcommit.

  • 関連する可能性があります: EJBTransactionManagementType.BEANは「トランザクション バリア」として機能します。現在のトランザクションを一時停止する可能性があります: Bean 管理のトランザクションを持つ EJB Bean が「トランザクションの障壁」として機能するのはなぜですか? ここ

したがって、トランザクション処理を修正する代わりに、同じ機能を提供するステートレス セッション Bean を追加し、これを (同期的に) 呼び出すことをお勧めします。その場合、これがコンテナー管理のトランザクションで機能しない理由がわかりません。したがって、実際には Bean の境界を越えたトランザクションになります。

于 2013-08-27T13:45:37.670 に答える