Написание сообщений с помощью Spring JmsTemplate с использованием TransactionManager - PullRequest
1 голос
/ 12 мая 2011

Используя Spring-JMS, можно получать сообщения в контексте внешней транзакции через DefaultMessageListenerContainer .

Однако единственный документированный способ написать сообщение - через JmsTemplate.send(…), и я не могу понять, как это можно принудительно использовать для данного TransactionManager.

Может ли кто-нибудь указать мне правильное направление?


Дополнительная информация: Обеспечение доступности менеджера транзакций (WebSphereUowTransactionManager) с использованием JmsTemplate.write против Oracle AQjmsFactory.getQueueConnectionFactory(dataSource) приводит к:

org.springframework.jms.UncategorizedJmsException: Uncategorized exception occured during JMS processing; nested exception is oracle.jms.AQjmsException: could not use local transaction commit in a global transaction
  at org.springframework.jms.support.JmsUtils.convertJmsAccessException(JmsUtils.java:316)
  at org.springframework.jms.support.JmsAccessor.convertJmsAccessException(JmsAccessor.java:168)
  at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:469)
  at org.springframework.jms.core.JmsTemplate.send(JmsTemplate.java:534)
Caused by: oracle.jms.AQjmsException: could not use local transaction commit in a global transaction
  at oracle.jms.AQjmsSession.commitNoCheck(AQjmsSession.java:1053)
  at oracle.jms.AQjmsSession.commit(AQjmsSession.java:1021)
  at org.springframework.jms.support.JmsUtils.commitIfNecessary(JmsUtils.java:217)
  at org.springframework.jms.core.JmsTemplate.doSend(JmsTemplate.java:573)
  at org.springframework.jms.core.JmsTemplate$3.doInJms(JmsTemplate.java:536)
  at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:466)
  ... 24 more
Caused by: java.sql.SQLException: could not use local transaction commit in a global transaction
  at oracle.jdbc.driver.PhysicalConnection.disallowGlobalTxnMode(PhysicalConnection.java:6647)
  at oracle.jdbc.driver.PhysicalConnection.commit(PhysicalConnection.java:3635)
  at oracle.jdbc.driver.PhysicalConnection.commit(PhysicalConnection.java:3680)
  at oracle.jdbc.OracleConnectionWrapper.commit(OracleConnectionWrapper.java:133)
  at oracle.jms.AQjmsSession.commitNoCheck(AQjmsSession.java:1049)
  ... 29 more

Так что, хотя у меня нет оснований сомневаться в приведенном ниже совете, я не могу его проверить, так как не могу понять, как заставить AQ JMS не пытаться выполнить коммит.Буду обновлять по мере того как я узнаю больше.

1 Ответ

7 голосов
/ 12 мая 2011

Насколько я понимаю, производители JMS по своей природе осуществляют транзакции через JTA. При отправке сообщения через JMS MessageProducer используется локальная для потока транзакция JTA (если она есть).

На это намекает руководство Spring ( раздел 21.2.5 ):

JmsTemplate также может использоваться с JtaTransactionManager и XMS-совместимым JMS ConnectionFactory для выполнения распределенных транзакций. Обратите внимание, что это требует использования диспетчера транзакций JTA, а также правильно настроенного XA ConnectionFactory.

Это также предлагает JmsAccessor.setSessionTransacted (суперкласс JmsTemplate) ( javadoc ):

Установите режим транзакции, который используется при создании сеанса JMS. По умолчанию установлено значение «ложь». Обратите внимание, что в транзакции JTA параметры, переданные методу create(Queue/Topic)Session(boolean transacted, int acknowledgeMode), не учитываются. В зависимости от контекста транзакции J2EE контейнер принимает свои собственные решения по этим значениям. Аналогично, эти параметры также не учитываются в локальной транзакции, поскольку в этом случае средство доступа работает с существующим сеансом JMS.

При установке этого флага в значение «true» будет использоваться короткая локальная транзакция JMS при выполнении вне управляемой транзакции и синхронизированная локальная транзакция JMS в случае наличия управляемой транзакции (кроме транзакции XA). Последний имеет эффект локальной транзакции JMS, управляемой вместе с основной транзакцией (которая может быть собственной транзакцией JDBC), причем транзакция JMS фиксируется сразу после основной транзакции.

Таким образом, запустив транзакцию JTA (т.е. используя API транзакций Spring с JtaTransactionManager) и вызвав JmsTemplate.send(...), вы отправите сообщение, связанное с этой транзакцией.

...