1

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

但是,编写消息的唯一记录方式是 via 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 不尝试提交。当我了解更多信息时会更新。

4

1 回答 1

7

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

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

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

JmsAccessor.setSessionTransacted(的超类JmsTemplate)(javadoc )也建议这样做:

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

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

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

于 2011-05-12T07:31:06.230 回答