2016-12-07 78 views
2

所以設置是以下幾點:Spring集成和JDBC在單個事務

<tx:advice id="txAdvice2" transaction-manager="dataSourceTransactionManager"> 
    <tx:attributes> 
     <tx:method name="*" rollback-for="Throwable" no-rollback-for="ListenerExecutionFailedException"/> 
    </tx:attributes> 
</tx:advice> 

<int-amqp:inbound-channel-adapter channel="input-channel" queue-names="probni" message-converter="jsonMessageConverter" 
            channel-transacted="true" 
            advice-chain="txAdvice2" /> 

<int:chain input-channel="input-channel" output-channel="output-channel"> 
    <int:service-activator ref="h1Handler" method="handle" /> 
    <int:service-activator ref="h2Handler" method="handle" /> 
    <int:service-activator ref="h3Handler" method="handle" /> 
    <int:splitter /> 
</int:chain> 

<int-amqp:outbound-channel-adapter channel="output-channel" exchange-name="outputit" amqp-template="rabbitTemplate" /> 

如果該線程的執行(因爲這一切鏈amqpIN過程-amqpOUT shold在單個線程執行)我扔ListenerExecutionFailedException期間, dataSourceTransactionManager將執行提交,但是amqp也會重傳消息,因爲異常會被傳播。

在這種情況下,我如何告訴兔子確認信息成功?

此外,我看到我必須放入不回滾 - 屬性實際的異常類,因爲我的內部異常只存儲在未由RuleBasedTransactionAttribute檢查的「cause」屬性中。

還有一兩件事,如果我的配置是這樣的:

<int-amqp:inbound-channel-adapter channel="input-channel" queue-names="probni" message-converter="jsonMessageConverter" 
            channel-transacted="true" 
            transaction-manager="dataSourceTransactionManager" 
            transaction-attribute="transactionAttribute" /> 

transactionAttribute這是RuleBasedTransactionAttribute完全不考慮和DataSourceTransactionManager對象總是rollbacked即使我有沒有回滾的正確設置。

謝謝!

回答

2

您可以將自定義ErrorHandler添加到偵聽器容器( ,您必須在外部配置容器並在 container屬性 中提供參考)。

默認的錯誤處理程序是一個ConditionalRejectingErrorHandlerDefaultExceptionStrategy即認爲某些LEFE導致異常致命:

private boolean isCauseFatal(Throwable cause) { 
     return cause instanceof MessageConversionException 
       || cause instanceof org.springframework.messaging.converter.MessageConversionException 
       || cause instanceof MethodArgumentNotValidException 
       || cause instanceof MethodArgumentTypeMismatchException 
       || cause instanceof NoSuchMethodException 
       || cause instanceof ClassCastException 
       || isUserCauseFatal(cause); 
    } 

與1.6.4版本開始,你可以繼承默認DefaultExceptionStrategy和您的事業(S)添加到isUserCauseFatal()

在1.6.4之前,您必須提供自己的FatalExceptionStrategy(或錯誤處理程序實現)。

對於致命原因,處理程序拋出一個AmqpRejectAndDontRequeueException,它告訴容器停止(而不是重新)消息。

編輯

順便說一句,有沒有必要爲你包裝異常,容器會爲你做的......

protected Exception wrapToListenerExecutionFailedExceptionIfNeeded(Exception e, Message message) { 
    if (!(e instanceof ListenerExecutionFailedException)) { 
     // Wrap exception to ListenerExecutionFailedException. 
     return new ListenerExecutionFailedException("Listener threw exception", e, message); 
    } 
    return e; 
} 

EDIT2

我的錯誤ErrorHandler可以使用error-handler屬性指定。

EDIT3

備選地,只是引發AmqpRejectAndDontRequeueException(其將被包裹在LEFE)。

+0

您不需要包裝異常;看我的編輯。另外,你可以使用'error-handler'屬性。 –

+0

感謝您的快速回復。明天會試試這個。如果我做rejectAndDontRequeue - 這會在DeadLetterQueue中結束嗎?我希望這被視爲普通的ACK,因爲我想這樣做,以防止消息被重新傳遞(至少傳遞一次+可能更多)。順便說一下,您還知道,爲什麼事務屬性在內部通道綁定器中提供時無法處理事務,但是如果作爲建議來應用,它的工作原理是什麼? (問題的第二部分)。 –

+0

這就是說,如果消息被重新傳遞,但jdbc已經被提交,我想拋出一個異常,它將回滾jdbc,但是ack rabbit消息(因爲我在處理管道末尾提交併確認)。 –