3
votes

I'm using Spring's DataSourceTransactionManager for transaction managment and JmsTemplate for sending messages to ActiveMQ queue. My problem is force to work in single transaction next algorithm:

Step 1: update DB;
Step 2: send message to queue;
Step 3: update DB;
Step 4: send message to queue.

As I understand from documentation for JmsTemplate, in my case I must set parameter "sessionTransacted" = true: 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.(c)

My jms-configuration file contains only this:

<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
        <property name="brokerURL" ref="url"/>
        <property name="userName" ref="username"/>
        <property name="password" ref="password"/>
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
        <property name="connectionFactory" ref="connectionFactory"/>
        <property name="defaultDestinationName" value="SomeQueue"/>
        <property name="sessionTransacted" value="true"/>
</bean>

After that I try to test it in simple way:

Case A:

@Transactional
public void sendMessageTransactionalErr(Object message, List<String> queueDestinationNames) throws Exception {
    sender.sendMessage(message, queueDestinationNames);
    throw new Exception("FatalException!");
}

Case B:

@Transactional
public void sendMessageTransactionalOK(Object message, List<String> queueDestinationNames) throws Exception {
    sender.sendMessage(message, queueDestinationNames);
}

But in both cases after request execution message is send to queue. Even if JDBC transaction rolled back, JMS transaction commit succesfull. What should I do to make it work as I need to?

1

1 Answers

2
votes

You need to use a transaction manager that handles BOTH your JMS transaction and database transaction. Your JMS transaction is separate from the database transaction.

I don't recall exactly, but when I had this problem I created an instance of org.springframework.jms.connection.JmsTransactionManager. Create a JTA transaction manager and make sure your it is aware of this AND the database transaction manager. Use @Transactional("jtaTransactionManager") for the annotation. I may have tried Bitronix or JOTM for this use case.

See Spring Integration and Transaction with JMS and DB

Reference: http://www.javaworld.com/article/2077963/open-source-tools/distributed-transactions-in-spring--with-and-without-xa.html?page=2