8

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)

KBR
  • 464
  • 1
  • 7
  • 24

1 Answers1

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.

Gary Russell
  • 166,535
  • 14
  • 146
  • 179
  • 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? – KBR Jan 02 '15 at 02:37
  • 1
    "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. – Gary Russell Jan 02 '15 at 14:46
  • Thanks Gary. Removing the CachingConnectionFactory and pointing the JMSTemplate and listener to same conn factory(jmsSecurityFactory in above configration ) worked. – KBR Jan 04 '15 at 19:56
  • 4
    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. – Gary Russell Jan 04 '15 at 20:33