使用 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 不尝试提交。当我了解更多时会更新。
Using Spring-JMS it is possible to receive messages within an external transaction context via the DefaultMessageListenerContainer.
However the only documented way to write a message is via JmsTemplate.send(…)
and I can't see how this can be coerced to use a given TransactionManager
.
Can anyone point me in the right direction?
More info: Ensuring a transaction manager is available (WebSphereUowTransactionManager
), using JmsTemplate.write
against an Oracle AQjmsFactory.getQueueConnectionFactory(dataSource)
results in:
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
So whilst I have no reason to doubt the advise below, I am not able to test it as I can't figure out how to get AQ JMS to not attempt a commit. Will update as I learn more.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我的理解是,JMS 生产者本质上是通过 JTA 进行交易的。通过通过 JMS
MessageProducer
发送消息,将使用线程本地 JTA 事务(如果存在)。Spring手册暗示了这一点(第21.2节.5):
JmsAccessor.setSessionTransacted
(JmsTemplate
的超类)也建议这样做(javadoc):因此,通过启动 JTA 事务(即通过使用带有
JtaTransactionManager
的 Spring 事务 API)并调用JmsTemplate.send(...)
,您将发送绑定到该事务的消息交易。My understanding is that JMS producers are inherently transacted via JTA. By sending a message via JMS
MessageProducer
, the thread-local JTA transaction is used (if one is present).This is hinting at by the Spring manual (section 21.2.5):
This is also suggested by
JmsAccessor.setSessionTransacted
(the superclass ofJmsTemplate
) (javadoc):So by start a JTA transaction (i.e. by using Spring's transaction API with
JtaTransactionManager
) and callingJmsTemplate.send(...)
, you will be sending the message bound to that transaction.