Активация MDB для сообщения JMS до фиксации транзакции JTA

Мне нужно синхронизировать транзакцию JTA с отправкой сообщения JMS - MDB должен быть активирован после фиксации транзакции клиента JTA. Это возможно при использовании XAConnectionFactory, но не работает в моем примере.

Пример сценария:

  • клиент веб-службы отправляет сообщение с кодом = 0
  • mdb получает сообщение и печатает: START: код (НОВАЯ ТРАНЗАКЦИЯ JTA)
  • mdb увеличивает код и печатает: SEND: %code + 1%
  • mdb отправить сообщение с новым значением кода
  • мдб сон
  • mdb print: КОНЕЦ кода
  • завершение mdb (ЗАВЕРШЕНИЕ ТРАНЗАКЦИИ)

Сценарий повторяется до кода ‹ 10. Ожидаю результат:

START: 0
SEND: 1
END: 0
START: 1
SEND: 2
END: 1
START: 2
SEND: 3
END: 2
etc..

но в настоящее время я получаю:

...
START: 4
SEND: 5
END: 3
START: 5
SEND: 6
END: 4
START: 6
SEND: 7
END: 5
END: 6

Мой код:

  • Клиент веб-сервиса

    @WebMethod
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void publish() {
        TestQueueUtil.sendToQueue(0);
    }
    
  • TestQueueUtil (клиент JMS)

    public static void sendToQueue(Integer code) {
      InitialContext initialContext;
      XAQueueConnection queueConnection = null;
      XAQueueSession queueSession = null;
    
      try {
        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
        initialContext = new InitialContext(env);
        XAConnectionFactory queueConnectionFactory = (XAConnectionFactory) initialContext.lookup("jms/dsk/ConnectionFactoryXA");
    
        queueConnection = (XAQueueConnection) queueConnectionFactory.createXAConnection();
        queueConnection.start();
    
        queueSession = queueConnection.createXAQueueSession();
        Queue queue = (Queue) initialContext.lookup("jms/dsk/TestQueue");
    
        //QueueSender sender =
        MessageProducer producer = queueSession.createProducer(queue);
        Message jmsMessage = queueSession.createMessage();
    
        jmsMessage.setIntProperty("code", code);
        producer.send(jmsMessage);
        producer.close();
        queueConnection.stop();
    
    } catch (Exception e) {
        throw new RuntimeException("sendToQueue", e);
    } finally {
        if (queueSession != null) {
            try {
                queueSession.close();
            } catch (Exception e) {
                //ignore
            }
        }
        if (queueConnection != null) {
            try {
                queueConnection.close();
            } catch (Exception e) {
                //ignore
            }
        }
      }
    
    }
    
  • TestQueueMDB

    @MessageDriven(mappedName = "jms/dsk/TestQueue", activationConfig = {
            @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
            @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
    })
    public class TestQueueMDB implements MessageListener {
    
        @Resource
        protected MessageDrivenContext messageDrivenContext;
    
        @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
        public void onMessage(Message message) {
            Integer code = null;
            try {
    
                code = message.getIntProperty("code");
                System.out.println("START: " + code);
                if (code < 10) {
                    Integer newcode = code + 1;
                    System.out.println("SEND: " + newcode);
                    TestQueueUtil.sendToQueue(newcode);
                    Thread.sleep(2000);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                System.out.println("END: " + code);
            }
        }
    }
    

Что я делаю неправильно?


person Dariusz Skrudlik    schedule 07.12.2011    source источник


Ответы (1)


Я обнаружил, что у меня нет контекста транзакции в MDB !!!

Когда я проверил идентификатор транзакции, позвонив

weblogic.transaction.TxHelper.getTransactionId() 

получил null, и при вызове messageDrivenContext.getRollbackOnly() получить исключение

java.lang.IllegalStateException: [EJB:010156]Illegal attempt to call EJBContext.getRollbackOnly() from an EJB that was not participating in a transaction.

Причиной тому была аннотация

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)

После удаления или изменения на

@TransactionAttribute(TransactionAttributeType.REQUIRED)

все работает нормально.

:)

person Dariusz Skrudlik    schedule 08.12.2011
comment
Это очень странные симптомы. Это правда, что MDB разрешают только транзакционные аннотации NOT_SUPPORTED или REQUIRED, но я бы предпочел ожидать, что при развертывании будет выдано исключение, чем молча игнорировать REQUIRES_NEW. Тем не менее, +1 за интересное продолжение. - person MaDa; 09.12.2011