单个事务中的Spring集成和JDBC

时间:2016-12-07 16:55:57

标签: spring jdbc transactions rabbitmq spring-integration

所以设置如下:

<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-process-amqpOUT shold在单个线程中执行)我抛出ListenerExecutionFailedException,dataSourceTransactionManager将执行提交,但是amqp也会重新排队消息,因为传播了异常。

在这种情况下,如何告诉兔子确认消息成功?

另外,我看到我必须在属性实际异常类中放入no-rollback-for,因为我的内部异常只存储在“cause”属性中,而RuleBasedTransactionAttribute没有检查它。

还有一件事,如果我像这样制作配置:

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

根本不考虑作为RuleBasedTransactionAttribute的transactionAttribute,即使我没有正确设置了回滚,也始终回滚dataSourceTransactionManager。

谢谢!

1 个答案:

答案 0 :(得分: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并将您的原因添加到isUserCauseFatal()

在1.6.4之前,您必须提供自己的FatalExceptionStrategy(或错误处理程序实现)。

对于致命原因,处理程序抛出AmqpRejectAndDontRequeueException,告诉容器nack(而不是重新排队)消息。

修改

顺便说一下,你不需要包装异常,容器会为你做那个......

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中)。