2
votes

I have a message driven channel adapter configured to pick messages from queue with acknowledge set to transacted. Is it possible to send different messages to different queues down stream holding the same transaction also have database inserts between in the flow?. If message delivery fails to any queue , the transaction must roll back (including database entries) as well the message send to other queues.

Example : queue(receive)--->insert Db-->send to(queue1,queue2.. etc sending different message to each queue)

if any send call fails for queue1, queue2 etc the transaction should roll back..

I am able to do the configuration with single queue (ie only with queue1). But how to do if multiple queues are involved and holding the transaction boundaries.

Thanks Vaidya

Below is the configuration

                                                              <int-jms:message-driven-channel-adapter
    id="MessageDrivenAdapter" channel="injmsChannel" destination="testQ"
    concurrent-consumers="5" max-concurrent-consumers="10" acknowledge="transacted"
    error-channel="Error" />

<int:channel id="injmsChannel" />

<int:chain input-channel="injmsChannel" id="Chain1">


    <int-jpa:retrieving-outbound-gateway
        entity-class="entity.TestTable8"
        entity-manager-factory="entityManagerFactory" id-expression="payload.getSno()">
        <int-jpa:transactional transaction-manager="transactionManager" />
    </int-jpa:retrieving-outbound-gateway>

    <int:recipient-list-router id="ROUTE_1_2">
        <int:recipient channel="SuccessChannel"
            selector-expression="payload.getSno()==1" />
            /> -->
    </int:recipient-list-router>

</int:chain>

<int:channel id="SuccessChannel" />


<int:chain id="MessageProcessingChain" input-channel="SuccessChannel"
    output-channel="putMsgChannel">

    <int:service-activator id="a1" ref="taskexe"
        method="processTable8_1" requires-reply="true" />

    <int-jpa:retrieving-outbound-gateway
        id="table7" entity-class="entity.TestTable7"
        entity-manager-factory="entityManagerFactory" id-expression="payload.getSno()">
        <int-jpa:transactional transaction-manager="transactionManager" />
    </int-jpa:retrieving-outbound-gateway>

    <int:service-activator id="a2" ref="taskexe"
        method="processTable8_2" requires-reply="true" />

    <int-jpa:updating-outbound-gateway
        id="table6" entity-class="entity.TestTable6"
        entity-manager-factory="entityManagerFactory" flush="true">
        <int-jpa:transactional transaction-manager="transactionManager" />
    </int-jpa:updating-outbound-gateway>

    <int:service-activator id="a3" ref="taskexe"
        method="processTable6_1" requires-reply="true" />

    <int-jpa:updating-outbound-gateway
        id="uptable6" entity-class="entity.TestTable6"
        entity-manager-factory="entityManagerFactory" flush="true">
        <int-jpa:transactional transaction-manager="transactionManager" />
    </int-jpa:updating-outbound-gateway>

    <int:service-activator id="a4" ref="taskexe"
        method="processTable6_2" requires-reply="true" />



    <int-jpa:updating-outbound-gateway
        id="uptable4" entity-class="entity.TestTable4"
        entity-manager-factory="entityManagerFactory" flush="true">
        <int-jpa:transactional transaction-manager="transactionManager" />
    </int-jpa:updating-outbound-gateway>



    <int:service-activator ref="taskexe" method="processTable4_1"
        requires-reply="true" />



</int:chain>

<int:channel id="putMsgChannel" />

<int-jms:outbound-channel-adapter id="sendsomemsg"
    channel="putMsgChannel" connection-factory="connectionFactory"
    session-transacted="true" destination-expression="headers['somequeue']" />

How to add another int-jms:outbound-channel-adapte for other queue having same transaction boundaries of message driven adapter?. Also flush=true been set so that message is not passed downstream if there is any jpa adapter exception.

1

1 Answers

1
votes

As long as the queue sends are performed using a JmsTemplate (including the use of a JMS outbound channel adapter), on the same thread, they will be performed in the same transactional session as the message-driven adapter's message delivery.

If you add the JDBC transaction manager to the message-driven adapter, its transaction will be synchronized with the JMS transaction.

This provides "Best Effort 1PC" as discussed in Dave Syer's JavaWorld article: Distributed transactions in Spring, with and without XA.

There is a small possibility that the DB commit will succeed and the JMS commit fails, so you need to deal with duplicates. To avoid that you need a full XA solution.