2016-12-07 48 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消息(因为我在处理管道末尾提交并确认)。 –