使用TransactionManager使用Spring JmsTemplate编写消息

使用Spring-JMS,可以通过DefaultMessageListenerContainer在外部事务上下文中接收消息。

但是, 编写消息的唯一记录方法是通过JmsTemplate.send(…) ,我无法看到如何强制使用给定的TransactionManager

谁能指出我正确的方向?


更多信息:确保事务管理器可用( WebSphereUowTransactionManager ),对Oracle AQjmsFactory.getQueueConnectionFactory(dataSource)使用JmsTemplate.write导致:

 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不尝试提交。 随着我了解更多,将会更新。

我的理解是JMS生产者本质上是通过JTA进行交易的。 通过JMS MessageProducer发送MessageProducer ,使用线程本地JTA事务(如果存在)。

这是春季手册( 第21.2.5节 )的暗示:

JmsTemplate还可以与JtaTransactionManager和支持XA的JMS ConnectionFactory以执行分布式事务。 请注意,这需要使用JTA事务管理器以及正确配置XA的ConnectionFactory

这也是JmsAccessor.setSessionTransactedJmsTemplate的超类)( javadoc )的建议:

设置创建JMS会话时使用的事务模式。 默认为“false”。 请注意,在JTA事务中,不考虑传递给create(Queue/Topic)Session(boolean transacted, int acknowledgeMode)方法的参数。 根据J2EE事务上下文,容器会自行决定这些值。 类似地,这些参数也不在本地管理的事务中被考虑,因为在这种情况下访问者在现有的JMS会话上操作。

将此标志设置为“true”将在托管事务外部运行时使用短的本地JMS事务,并且在托管事务(XA事务除外)存在时使用同步的本地JMS事务。 后者具有与主事务(可能是本机JDBC事务)一起管理的本地JMS事务的效果,JMS事务在主事务之后立即提交。

因此,通过启动JTA事务(即通过使用Spring的事务API和JtaTransactionManager )并调用JmsTemplate.send(...) ,您将发送绑定到该事务的消息。