Transaction Management in Spring JMS listener
Asked Answered
P

1

9

I have a spring JMS listener which is listening to queue . Once the message arrives at the input queue , it does certain processing on the message and puts the messages to multiple other queues for further processing (we may call these other queues as output queues) . While its posting to other output queues, in case posting the message to one of the output queues may fail due to any reason , I want to make sure that other posts to output queues which are done prior to failure gets rolled back. Basically I want to ensure it as atomic operation . is there any annotation/configuration on the listener/container that I can use to achieve this in single transaction.?

Here Is the configuration that I am using

<jms:listener-container acknowledge="transacted" cache="session" connection-factory="jmsSecurityFactory" concurrency="1" container-type="default" container-class="abc.xyz">
<jms:listener id="listenerId" destination="inputQueue" ref="" />
</jms:listener-container>
<beans:bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<beans:property name="sessionTransacted" value="true"></beans:property>
<beans:property name="connectionFactory" ref="inCachingConnectionFactory"></beans:property>
</beans:bean>
<beans:bean id="inCachingConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
    <beans:property name="targetConnectionFactory" ref="jmsSecurityFactory" />
</beans:bean>
<beans:bean id="jmsSecurityFactory"
    class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
    <beans:property name="targetConnectionFactory" ref="jmsConnectionFactory" />
    <beans:property name="username" value=" " />
    <beans:property name="password" value=" " />
</beans:bean>
<beans:bean id="jmsConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
    <beans:property name="hostName" value="${mq.conn.hostName}" />
    <beans:property name="port" value="${mq.conn.hostPort}" />
    <beans:property name="queueManager" value="${mq.conn.queueManager}" />
    <beans:property name="channel" value="${mq.conn.channel}" />
    <beans:property name="transportType" value="${mq.conn.transportType}" />
    <beans:property name="useConnectionPooling" value="true"></beans:property>
</beans:bean>

it looks like JMS template and listener container both refer to same connection factory bean (jmsConnectionFactory)

Parquetry answered 2/1, 2015 at 0:33 Comment(0)
S
8

Set acknowledge="transacted" on the listener container; any downstream operations on the same thread, using a JmsTemplate (configured with the same connection factory) will use the container's Session and any failure will cause all JMS operations to roll back. The session will be committed by the container on success.

Sorcerer answered 2/1, 2015 at 1:48 Comment(4)
Thanks Gary. I have posted the configuration . It looks like acknowledge attribute is set as intended and also JMS template and container both are using the same connection factory ulitmately. Do you see any issue there?Parquetry
"Ulitmately" doesn't cut it; it has to be a reference to the same connection factory for the template to use the container's session.Sorcerer
Thanks Gary. Removing the CachingConnectionFactory and pointing the JMSTemplate and listener to same conn factory(jmsSecurityFactory in above configration ) worked.Parquetry
You may want to consider retaining the CCF so the JmsTemplate producers can be cached (for efficiency). However, you must set cacheConsumers to false, especially when using variable concurrency on the container. You don't want to cache consumers in the CCF, but caching producers provides great benefit.Sorcerer

© 2022 - 2024 — McMap. All rights reserved.