2016-08-19 78 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'下的問題中插入的解決方法,並會很感激您的意見。 –