【问题标题】:Spring integration and JDBC in single transaction单个事务中的 Spring 集成和 JDBC
【发布时间】:2017-04-22 17:33:01
【问题描述】:

所以设置如下:

<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 也会重新排队消息,因为传播了异常。

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

另外,我看到我必须放入 no-rollback-for 属性实际异常类,因为我的内部异常仅存储在 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,即使我正确设置了 no-rollback-for,也始终回滚 dataSourceTransactionManager。

谢谢!

【问题讨论】:

    标签: spring jdbc transactions rabbitmq spring-integration


    【解决方案1】:

    您可以将自定义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 中)。

    【讨论】:

    • 你不需要包装异常;看我的编辑。此外,您可以使用error-handler 属性。
    • 感谢您的快速回复。明天试试这个。如果我做rejectAndDontRequeue - 这最终会出现在DeadLetterQueue 中吗?我希望将其视为普通 ACK,因为我想这样做以防重新传递该消息(至少传递一次 + 可能更多)。顺便说一句,您是否也知道为什么在 inbound-channel-adater 中提供 transaction-attribute 时不能处理事务,但如果作为建议应用则可以工作? (问题的第二部分)。
    • 也就是说,如果消息被重新传递但 jdbc 已经提交,我想抛出一个异常,该异常将回滚 jdbc 但确认兔子消息(因为我在处理管道结束时提交并确认) .
    • 是的,如果这样配置,它将进入 DLQ。如果错误处理程序抛出ImmediateAcknowledgeAmqpException,则消息将被正常确认。我不确定你的第二个问题; AFAICT 它应该可以正常工作,但我必须进行一些测试;但我这周不在城里。 ImmediateAcknowledgeAmqpException 必须包含在 LEFE 中。异常 javadoc 中的注释“并且不再使用任何消息”指的是 txSize 处理 - 这并不意味着处理将停止。
    • 第二个问题是bug;容器不会在事务属性上调用rollbackOn 方法。请打开JIRA Issue
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-03
    • 2014-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多