2016-08-19 56 views
1

我的流程设置是这样的:交易完成不确定性

<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> 
在某些情况下的链2的交易链1的交易前完成

现在,我有DB_state_1在数据库中。

如何在链1的消息发送到output-channel之前强制链1的事务完成?

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

EDIT CURRENT WORKAROUND

@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); 
     } 
    } 
} 

回答

1

你的问题,你有两个队列,这是对自己的轮询线程处理。

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

考虑使用<request-handler-advice-chain>而不是<tx:advice>代替<DB_update_state1/>。在这种情况下,只有数据库更新将被包装到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

编辑

我们做了一些调查,看起来像你不要,如果你的QueueChannel”不是个有那么多的选择t基于交易MessageStore。在这种情况下,您应该确保TX QueueChannel的“轮询”部分处于READ_COMMITED模式,其中“发送”部分也具有TX边界。即使我们在发送提交之前发送消息到该队列,直到真正的提交才会被用于轮询。但是,是的,它只适用于交易MessageStore,如JdbcChannelMessageStore

如果您不使用这种方式,则不应扩展比TX资源更广泛的事务边界。

为了总结这些你JMS和DB服务,我们建议的配置是这样相同的事务:

<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> 
+0

我已经编辑我的例子。通常,带有代表事务的轮询器的链具有其他处理程序,其中一些也是事务性资源。所以我需要在消息被发送到链的'output-channel'之前完成链的完整事务。 –

+0

请在我的回答中查看'EDIT'。 –

+0

这个解决方案的工作原理,但我们有另一个问题[见这篇文章](http://stackoverflow.com/questions/39097422/dataaccessexception-not-wrapped-in-messagingexception)。目前我们正在使用'EDIT CURRENT WORKAROUND'下的问题中插入的解决方法,并会很感激您的意见。 –