交易完成不确定 [英] Transaction completion not deterministic

查看:31
本文介绍了交易完成不确定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的流程设置如下所示:

My flow setup looks like this:

<int:channel id="channel1">
    <int:queue/>
</int:channel>
<int:channel id="channel2">
    <int:queue/>
</int:channel>

<int:chain id="chain1" input-channel="channel1" output-channel="channel2">
    <int:poller>
        <int:transactional propagation="REQUIRES_NEW"/>
    </int:poller>
    <Authorzier/>
    <JMS_put1/>
    <DB_update_state1/>
</int:chain>

<int:chain id="chain2" input-channel="channel2" output-channel="nullChannel">
    <int:poller>
        <int:transactional propagation="REQUIRES_NEW"/>
    </int:poller>
    <Transformer/>
    <JMS_put2/>
    <DB_update_state2/>
</int:chain>

现在在某些情况下chain2的事务在chain1的事务之前完成并且我在数据库中有DB_state_1.

Now in some cases the the transaction of chain2 completes before the transaction of chain1 and I have DB_state_1 in the database.

如何在消息发送到chain1的output-channel之前强制chain1的交易完成?

How can I force the transaction of chain1 to complete before the message is sent to the output-channel of chain1?

我知道我可以使用 TransactionSynchronization 将消息发送到 afterCommit() 中的 channel2,但我认为必须有一个更优雅的解决方案.

I know I can use a TransactionSynchronization that sends the message to channel2 in afterCommit() but I assume there must be a more elegant solution.

编辑当前的解决方法

@ServiceActivator
public void sendToDestinationFlow(Message<?> message) {
    TxSenderSyncer s = new TxSenderSyncer(message, this.channel, this.errorChannel);
    TransactionSynchronizationManager.registerSynchronization(s);
}

private static class TxSenderSyncer implements TransactionSynchronization {

    private Message<?> message;
    private MessageChannel channel;
    private MessageChannel errorChannel;

    public TxSenderSyncer(Message<?> message, MessageChannel channel, MessageChannel errorChannel) {
        this.message = message;
        this.channel = channel;
        this.errorChannel = errorChannel;
    }

    @Override
    public void afterCompletion(int paramInt) {
        if (paramInt == STATUS_ROLLED_BACK) {
            errorChannel.send(MessageBuilder.withPayload(new MessagingException(message, "Transaction rolled back")).build());
        } else {
            channel.send(message);
        }
    }
 }

推荐答案

您的问题是您有两个队列,它们在自己的轮询线程上处理.

Your problem that you have two queues, which are processed on their own poller threads.

因此,即使在第一个链的线程中的工作结束之前,消息也可以发送到第二个并在那里处理.

Therefore message can be send to the second and processed there even before the end of the work in thread of the first chain.

考虑将 一起用于该 代码> 代替.在这种情况下,只有 DB 更新将被包装到 TX.发送到 output-channel 是在 handleRequestMessage 工作完成后引起的:http://docs.spring.io/spring-integration/docs/4.3.1.RELEASE/reference/html/messaging-endpoints-chapter.html#message-handler-advice-chain

Consider to use <request-handler-advice-chain> with <tx:advice> for that <DB_update_state1/> instead. In this case only DB update will be wrapped to TX. The send to the output-channel is caused after the finish of work on the handleRequestMessage: http://docs.spring.io/spring-integration/docs/4.3.1.RELEASE/reference/html/messaging-endpoints-chapter.html#message-handler-advice-chain

编辑

我们做了一些调查,如果您的 QueueChannel 不是基于事务性的 MessageStore,那么您似乎没有太多选择.在这种情况下,您应该确保 TX QueueChannel 的轮询"部分处于 READ_COMMITED 模式,其中发送"部分也在 TX 边界内.即使我们在 TX 提交之前将消息发送到该队列,它在真正提交之前也无法用于轮询.但是,是的,它仅适用于事务 MessageStore,例如 JdbcChannelMessageStore.

We did some investigation, and that looks like you don't have so much choice if your QueueChannel isn't based on the transactional MessageStore. In that case you should just be sure that "poll" part of that TX QueueChannel is in mode READ_COMMITED, where the "send" part is withing TX boundaries as well. And even we send message to that queue before TX commit it won't be available for polling until real commit. But, yeah, it works only for transactional MessageStore like JdbcChannelMessageStore.

如果您不使用此类,则不应将事务边界扩展到比 TX 资源更宽的范围.

If you don't use such that, you shouldn't extend transaction boundaries broader than TX resources.

为了将您的 JMS 和 DB 服务包装到同一个事务中,我们建议如下配置:

To wrap those your JMS and DB services to the same transaction we propose the config like this:

<service-activator ref="txGateway" input-channel="channel1" output-channel="channel2">
    <poller/>
    <request-handler-advice-chain>
        <tx:advice/>
    </request-handler-advice-chain>
</service-activator>

<gateway id="txGateway" default-request-channel="txChain"/>

<chain input-channel="txChain">
    <Authorzier/>
    <JMS_put1/>
    <DB_update_state1/>
</chain> 

这篇关于交易完成不确定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆