使用TransactionManager使用Spring JmsTemplate编写消息 [英] Writing messages with Spring JmsTemplate using a TransactionManager
问题描述
使用Spring-JMS可以通过 DefaultMessageListenerContainer 。
Using Spring-JMS it is possible to receive messages within an external transaction context via the DefaultMessageListenerContainer.
然而写消息的唯一记录方式是通过 JmsTemplate.send(...)
我无法看到如何强制使用给定的 TransactionManager
。
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?
更多信息:确保事务管理器可用( WebSphereUowTransactionManager
),使用 JmsTemplate.write
针对Oracle AQjmsFactory.getQueueConnectionFactory(dataSource)
导致:
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
因此,虽然我没有理由怀疑下面的建议,但我无法对其进行测试因为我无法弄清楚如何让AQ JMS不尝试提交。随着我的了解更新将会更新。
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.
推荐答案
我的理解是JMS生产者通过JTA进行固有交易。通过JMS MessageProducer
发送消息,使用线程本地JTA事务(如果存在)。
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).
这是Spring手册的暗示(部分21.2.5 ):
This is hinting at by the Spring manual (section 21.2.5):
JmsTemplate
也可以用于用于执行分布式事务的JtaTransactionManager
和支持XA的JMSConnectionFactory
。请注意,这需要使用JTA事务管理器以及正确配置XA的ConnectionFactory
。
JmsTemplate
can also be used with theJtaTransactionManager
and an XA-capable JMSConnectionFactory
for performing distributed transactions. Note that this requires the use of a JTA transaction manager as well as a properly XA-configuredConnectionFactory
.
这也是由 JmsAccessor.setSessionTransacted
( JmsTemplate
的超类)( javadoc ):
This is also suggested by JmsAccessor.setSessionTransacted
(the superclass of JmsTemplate
) (javadoc):
设置创建JMS会话时使用的事务模式。默认为false。
请注意,在JTA事务中,传递给create(Queue / Topic)Session(boolean transacted,int acknowledgeMode)
方法的参数不会被采用帐户。根据J2EE事务上下文,容器会自行决定这些值。类似地,这些参数也不会在本地管理的事务中考虑,因为在这种情况下访问者在现有的JMS会话上运行。
Set the transaction mode that is used when creating a JMS Session. Default is "false". Note that within a JTA transaction, the parameters passed to
create(Queue/Topic)Session(boolean transacted, int acknowledgeMode)
method are not taken into account. Depending on the J2EE transaction context, the container makes its own decisions on these values. Analogously, these parameters are not taken into account within a locally managed transaction either, since the accessor operates on an existing JMS Session in this case.
将此标志设置为true将在托管事务外部运行时使用短本地JMS事务,在托管事务时使用同步本地JMS事务(除了XA交易之外)。后者具有与主事务(可能是本机JDBC事务)一起管理的本地JMS事务的效果,JMS事务在主事务之后立即提交。
Setting this flag to "true" will use a short local JMS transaction when running outside of a managed transaction, and a synchronized local JMS transaction in case of a managed transaction (other than an XA transaction) being present. The latter has the effect of a local JMS transaction being managed alongside the main transaction (which might be a native JDBC transaction), with the JMS transaction committing right after the main transaction.
因此,通过启动JTA事务(即使用Spring的事务API与 JtaTransactionManager
)并调用 JmsTemplate.send (...)
,您将发送绑定到该交易的消息。
So by start a JTA transaction (i.e. by using Spring's transaction API with JtaTransactionManager
) and calling JmsTemplate.send(...)
, you will be sending the message bound to that transaction.
这篇关于使用TransactionManager使用Spring JmsTemplate编写消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!