1
votes

We need to persist message from a JMS Queue to a database in a transaction ensuring that JMS message is not acknowledged in case any error is thrown during DB persist. Based on the solution provided here- Transaction handling while using message driven channel adapter & service activator Below is the approach I arrived at

<int-jms:message-driven-channel-adapter id="jmsIn"
    transaction-manager="transactionManager"
    connection-factory="sConnectionFactory"
    destination-name="emsQueue"
    acknowledge="transacted" channel="jmsInChannel"/>

<int:channel id=" jmsInChannel " />

<bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="org.hsqldb.jdbcDriver" />
    <property name="url" value="jdbc:hsqldb:mem:testdb" />
</bean>

<!-- Transaction manager for a datasource -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
</bean>

    <bean id="sconnectionFactory"       class="org.springframework.jms.connection.TransactionAwareConnectionFactoryProxy">
        <property name="targetConnectionFactory">
            <bean class="project.TestConnectionFactory">

            </bean>
        </property>
        <property name="synchedLocalTransactionAllowed" value="true" />
    </bean>

Please confirm if the understanding is correct. Also, have the below queries

  1. Is the TransactionAwareConnectionFactoryProxy necessary in this scenario
  2. JMS Queue and JDBC are two separate transactional resources. Is injecting jdbc transaction manager into JMS adapter as shown in this example equivalent to using a ChainedTransactionManager(chaining JMS Transaction Mananger and JDBC transaction manager)
1

1 Answers

1
votes

For TransactionAwareConnectionFactoryProxy, please, consult its JavaDocs:

 * Proxy for a target CCI {@link javax.resource.cci.ConnectionFactory}, adding
 * awareness of Spring-managed transactions. Similar to a transactional JNDI
 * ConnectionFactory as provided by a Java EE server.
 *
 * <p>Data access code that should remain unaware of Spring's data access support
 * can work with this proxy to seamlessly participate in Spring-managed transactions.
 * Note that the transaction manager, for example the {@link CciLocalTransactionManager},
 * still needs to work with underlying ConnectionFactory, <i>not</i> with this proxy.

I'm not sure how is that related to your request about JMS+DB transaction, but I think you should worry about transaction manager which supports both those transactional resources.

For this purpose Spring suggests JtaTransactionManager for XA transactions. Or you can consider to use ChainedTransactionManager based on the Dave Syer article: http://www.javaworld.com/article/2077963/open-source-tools/distributed-transactions-in-spring--with-and-without-xa.html

UPDATE

If local transaction are fine for you, you really can go ahead with the TransactionAwareConnectionFactoryProxy and its synchedLocalTransactionAllowed to true. And, of course, use that DataSourceTransactionManager directly from the <int-jms:message-driven-channel-adapter>.

Otherwise you have to go with the ChainedTransactionManager. This solution really adds some overhead over the first TransactionAwareConnectionFactoryProxy-based one.