使用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的JMSConnectionFactory
以执行分布式事务。 请注意,这需要使用JTA事务管理器以及正确配置XA的ConnectionFactory
。
这也是JmsAccessor.setSessionTransacted
( JmsTemplate
的超类)( 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(...)
,您将发送绑定到该事务的消息。