如何在多个Spring集成通道之间传播单个事务

时间:2016-10-14 14:50:26

标签: spring spring-integration spring-transactions

在我的应用程序中,我使用多个弹簧集成通道。我的要求是所有通道中的db操作应该作为单个事务工作。如果所有通道中的db操作都成功,那么只有事务应该提交,否则所有数据库操作都应该回滚。 这是我的代码片段:

MyFirstService.java

    @Transactional
    public class MyFirstService {

        @Resource
        private MyFirstRepository myFirstRepository;

        @Transactional(propagation = Propagation.REQUIRED)
        @ServiceActivator(inputChannel = "my-first-servie-input-channel",
                          outputChannel = "my-first-servie-output-channel")
        public String saveData(final MyEntity myEntity) {
             myFirstRepository.save(myEntity);
        }
    }

MySecondService.java

 @Transactional
 public class MySecondService {

    @Resource
    private MySecondRepository mySecondRepository;

    @Transactional(propagation = Propagation.REQUIRED)
    @ServiceActivator(inputChannel = "my-first-servie-output-channel",
                      outputChannel = "my-Second-servie-output-channel")
    public String saveEntity(final MyTestEntity myTestEntity) {
         mySecondRepository.save(myTestEntity);
    }
}

弹簧整合-context.xml中         

    <int:chain input-channel="transaction-inbound-channel" output-channel="my-first-servie-input-channel">
    </int:chain>
<int-amqp:inbound-channel-adapter
            channel="transaction-inbound-channel"
            queue-names="sample.queue"
            concurrent-consumers="5"
            error-channel="failed-channel"
            connection-factory="rabbitConnectionFactory"
            mapped-request-headers="*" channel-transacted="true"/>

    <rabbit:connection-factory
            id="rabbitConnectionFactory"
            connection-factory="rcf"
            host="${spring.rabbitmq.host}"
            port="${spring.rabbitmq.port}"
            username="${spring.rabbitmq.username}"
            password="${spring.rabbitmq.password}"
            />
    <bean id="rcf" class="com.rabbitmq.client.ConnectionFactory">
        <property name="host" value="${spring.rabbitmq.host}"/>
        <property name="requestedHeartbeat" value="10" />
    </bean>

因此,在上面的代码中,如果mySecondRepository.save(myTestEntity);失败,myFirstRepository.save(myEntity);应该回滚。

我没有在我的应用程序中的任何地方使用BarrierMessageHandler。 我在配置类中添加了@EnableTransactionManagement

即使我尝试channel-transacted="true",仍然没有运气。我在这里错过了什么吗?

我找到了在同一服务的多个方法之间传播单个事务的解决方案 https://softwareengineering.stackexchange.com/questions/163569/how-to-manage-2-dao-methods-in-a-single-transaction 但不是在多个渠道之间。有人可以帮助我实现这一目标。 提前致谢。

1 个答案:

答案 0 :(得分:0)

您不关心。无论如何,消息通道操作都是Java方法。所以,同样的TX包装也适用于此。

只关注你应该记住TX是线程限制的,如果你将消息转移到另一个线程,ExecutorChannelQueueChannelPublishSubscribeChannel {{1}等等,TX将被提交,因为你离开了保持线程。

因此,如果您的Executormy-first-servie-output-channelmy-first-servie-output-channel,那么一切正常,您的TX也将包装第二个存储库调用。只是因为一切都在同一个线程中完成。

当然,使用DirectChannel有一个技巧,它可以暂停一个线程,例如使用事务并等待触发器释放它,因此,提交TX。

修改

对于从MessageDriven Consumer到直接下游流的传播事务,您应该在那里提供事务。

BarrierMessageHandler是特定的,并且是RabbitMQ频道的本地特征。它与您的存储库完全无关。

为此,channel-transacted支持:

<int-amqp:inbound-channel-adapter>

<xsd:attribute name="transaction-manager" type="xsd:string"> <xsd:annotation> <xsd:appinfo> <xsd:documentation> The PlatformTransactionManager to use when the Consumer receives the AMQP Message and the Listener is invoked. </xsd:documentation> <tool:annotation kind="ref"> <tool:expected-type type="org.springframework.transaction.PlatformTransactionManager"/> </tool:annotation> </xsd:appinfo> </xsd:annotation> </xsd:attribute> 可以是对您的下游服务足够的任何实现。