【问题标题】:Mule ESB 3.3 Exception Strategies & Rollback baffling behaviourMule ESB 3.3 异常策略和回滚莫名其妙的行为
【发布时间】:2014-10-24 00:32:30
【问题描述】:

设置:
表:CREATE TABLE test (id int PRIMARY KEY NOT NULL, name varchar(25));

基本测试流程:

前提条件:数据库已有id=2的记录(强制SqlException)

案例 1:

按原样调用基本流程时,由于主键冲突,第二次插入失败,第一次插入回滚。似乎是一种合理的默认行为。

案例 2:

通过添加回滚异常策略来修改基本流程,并在异常策略中添加一个记录器,以便在调用它时打印一些内容。
调用流时,由于主键冲突,第二次插入失败,第一次插入被回滚永远不会调用 RollbackExceptionStrategy!
几乎没有人会期待。

所以这里的问题是:为什么不调用回滚异常策略以及我需要做什么才能调用它?

案例 3:

通过添加捕获异常策略来修改基本流程,并在异常策略中添加一个记录器,以便在调用它时打印一些内容。
调用流时,由于主键违规,第二次插入失败。这次调用了异常策略,但现在事务没有回滚。

这里的问题是:为什么事务没有被回滚以及如何在不同于回滚策略的异常策略中强制回滚?

任何帮助将不胜感激


Edit1:这是流程的完整 xml(仅基本情况):

<mule>
    <spring:beans>
        <spring:bean id="dataSource" name="dataSource" class="org.enhydra.jdbc.standard.StandardDataSource" destroy-method="shutdown">
            <spring:property name="driverName" value="org.h2.Driver" />
            <spring:property name="url" value="jdbc:h2:tcp://localhost/~/mule" />
            <spring:property name="user" value="sa" />
            <spring:property name="password">
                <spring:value></spring:value>
            </spring:property>
        </spring:bean>

        <spring:bean id="transactionFactory" name="transactionFactory" class="org.mule.transport.jdbc.JdbcTransactionFactory" />

    </spring:beans>

    <jdbc:connector name="dbConnector" dataSource-ref="dataSource" validateConnections="true" queryTimeout="-1" pollingFrequency="0" doc:name="Database" />

    <flow name="TriggerFlow" doc:name="TriggerFlow">
        <http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" doc:name="HTTP" />
        <vm:outbound-endpoint exchange-pattern="request-response" path="txFlow" doc:name="VM" />
    </flow>

    <flow name="TxFlow" doc:name="case1Flow">
        <vm:inbound-endpoint exchange-pattern="request-response" path="txFlow" doc:name="case1">
            <custom-transaction factory-ref="transactionFactory" action="ALWAYS_BEGIN" timeout="10" />
        </vm:inbound-endpoint>
        <jdbc:outbound-endpoint exchange-pattern="request-response" queryKey="insert" queryTimeout="-1" connector-ref="dbConnector" doc:name="insert into test values (1, 'Test 1')">
            <jdbc:transaction action="ALWAYS_JOIN" />
            <jdbc:query key="insert" value="insert into test values (1, 'Test 1')" />
        </jdbc:outbound-endpoint>
        <jdbc:outbound-endpoint exchange-pattern="request-response" queryKey="insert2" queryTimeout="-1" connector-ref="dbConnector" doc:name="insert into test values (2, 'Test 2')">
            <jdbc:transaction action="ALWAYS_JOIN" />
            <jdbc:query key="insert2" value="insert into test values (2, 'Test 2')" />
        </jdbc:outbound-endpoint>
    </flow>

</mule>

Edit2:事实证明,案例 2 孤立地工作,但它不适用于更复杂的流程,例如:

<mule>
    <spring:beans>
        <spring:bean id="dataSource" name="dataSource" class="org.enhydra.jdbc.standard.StandardDataSource" destroy-method="shutdown">
            <spring:property name="driverName" value="org.h2.Driver" />
            <spring:property name="url" value="jdbc:h2:tcp://localhost/~/mule" />
            <spring:property name="user" value="sa" />
            <spring:property name="password">
                <spring:value></spring:value>
            </spring:property>
        </spring:bean>

        <spring:bean id="transactionFactory" name="transactionFactory" class="org.mule.transport.jdbc.JdbcTransactionFactory" />

    </spring:beans>

    <jdbc:connector name="dbConnector" dataSource-ref="dataSource" validateConnections="true" queryTimeout="-1" pollingFrequency="0" doc:name="Database" />

    <flow name="TriggerTxFlow" doc:name="TriggerTxFlow">
        <http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" doc:name="HTTP" />
        <set-variable variableName="flow" value="#[message.inboundProperties['http.query.params']['flow']]" doc:name="Variable"/>
        <vm:outbound-endpoint exchange-pattern="request-response" path="#[flow]" doc:name="VM" />
    </flow>

    <flow name="case1Flow" doc:name="case1Flow">
        <vm:inbound-endpoint exchange-pattern="request-response" path="case1" doc:name="case1">
            <custom-transaction factory-ref="transactionFactory" action="ALWAYS_BEGIN" timeout="10" />
        </vm:inbound-endpoint>
        <jdbc:outbound-endpoint exchange-pattern="request-response" queryKey="insert" queryTimeout="-1" connector-ref="dbConnector" doc:name="insert into test values (1, 'Test 1')">
            <jdbc:transaction action="ALWAYS_JOIN" />
            <jdbc:query key="insert" value="insert into test values (1, 'Test 1')" />
        </jdbc:outbound-endpoint>
        <jdbc:outbound-endpoint exchange-pattern="request-response" queryKey="insert2" queryTimeout="-1" connector-ref="dbConnector" doc:name="insert into test values (2, 'Test 2')">
            <jdbc:transaction action="ALWAYS_JOIN" />
            <jdbc:query key="insert2" value="insert into test values (2, 'Test 2')" />
        </jdbc:outbound-endpoint>
    </flow>

    <flow name="case2Flow" doc:name="case2Flow">
        <vm:inbound-endpoint exchange-pattern="request-response" path="case2" doc:name="case2">
            <custom-transaction factory-ref="transactionFactory" action="ALWAYS_BEGIN" timeout="10" />
        </vm:inbound-endpoint>
        <jdbc:outbound-endpoint exchange-pattern="request-response" queryKey="insert" queryTimeout="-1" connector-ref="dbConnector" doc:name="Database">
            <jdbc:transaction action="ALWAYS_JOIN" />
            <jdbc:query key="insert" value="insert into test values (1, 'Test 1')" />
        </jdbc:outbound-endpoint>
        <jdbc:outbound-endpoint exchange-pattern="request-response" queryKey="insert2" queryTimeout="-1" connector-ref="dbConnector" doc:name="Database">
            <jdbc:transaction action="ALWAYS_JOIN" />
            <jdbc:query key="insert2" value="insert into test values (2, 'Test 2')" />
        </jdbc:outbound-endpoint>
        <rollback-exception-strategy doc:name="Rollback Exception Strategy" enableNotifications="false" maxRedeliveryAttempts="0">
            <on-redelivery-attempts-exceeded doc:name="Redelivery exhausted">
                <logger message="========= Inside Exception Strategy =========" level="INFO" doc:name="Logger"/>
            </on-redelivery-attempts-exceeded>
        </rollback-exception-strategy>
    </flow>

    <flow name="case3Flow" doc:name="case3Flow">
        <vm:inbound-endpoint exchange-pattern="request-response" path="case3" doc:name="VM">
            <custom-transaction factory-ref="transactionFactory" action="ALWAYS_BEGIN" timeout="10" />
        </vm:inbound-endpoint>
        <jdbc:outbound-endpoint exchange-pattern="request-response" queryKey="insert" queryTimeout="-1" connector-ref="dbConnector" doc:name="Database">
            <jdbc:transaction action="ALWAYS_JOIN" />
            <jdbc:query key="insert" value="insert into test values (1, 'Test 1')" />
        </jdbc:outbound-endpoint>
        <jdbc:outbound-endpoint exchange-pattern="request-response" queryKey="insert2" queryTimeout="-1" connector-ref="dbConnector" doc:name="Database">
            <jdbc:transaction action="ALWAYS_JOIN" />
            <jdbc:query key="insert2" value="insert into test values (2, 'Test 2')" />
        </jdbc:outbound-endpoint>
        <catch-exception-strategy doc:name="Catch Exception Strategy">
            <logger message="========= Inside Exception Strategy =========" level="INFO" doc:name="Logger"/>
        </catch-exception-strategy>
    </flow>

</mule>

【问题讨论】:

    标签: transactions esb mule rollback


    【解决方案1】:

    案例 1:耶!

    案例 2

    为什么不调用回滚异常策略?我需要做什么才能调用它?

    根据doc 应该调用该策略。这可能是您这边的配置问题,因为如果我添加:

    <rollback-exception-strategy>
        <logger message="---> In Rollback exception strategy!!!" />
    </rollback-exception-strategy>
    

    到“TxFlow”,我可以看到控制台中记录的文本。

    案例 3

    为什么事务没有回滚?

    这就是Catch Exception Strategy的主要目的,来自doc

    确保在发生错误时不会回滚由流处理的事务(即永远不会“回滚”事务以重新尝试处理;Mule 提交事务。)

    如何在不同于回滚策略的异常策略中强制回滚

    我不认为你可以。您可以尝试从策略中抛出异常,但恐怕当时事务已经提交。

    【讨论】:

    • 我刚刚为基本案例添加了流的 XML。它不是内存数据库,但设置起来非常容易。只需像这样触发 h2 db:java -cp h2-1.3.170.jar org.h2.tools.Server (repo2.maven.org/maven2/com/h2database/h2/1.3.170/h2-1.3.170.jar)。
    • 这太棒了,我正在研究它。
    • 谢谢大卫,你是对的。案例 2 孤立地工作,但在更复杂的流程中却没有。我刚刚添加了用于测试的实际流程。它包括3个案例。您将每个传递参数调用到触发器流,如下所示:localhost:8081/?flow=case2
    • 等等,你在rollback-exception-strategy中使用on-redelivery-attempts-exceeded:你从来没有提到过。您还可以在入站 VM 端点上使用 JDBC 事务工厂。您是否不希望在 VM 和 JDBC 之间进行 XA 事务,以便 VM 交付也回滚,从而导致重新交付,从而可能触发 on-redelivery-attempts-exceeded
    • 天哪,当我拖动时,我没有注意到记录器进入了 而不是 标记的主体-n-把它丢在骡工作室!大卫,我怎么付钱给你?你回答每一个骡子的问题。你真的应该开始向我收费了。
    【解决方案2】:

    试试这个在 ES 中强制回滚:

    <custom-exception-strategy class="..." >
        <rollback-transaction exception-pattern="*"/>
    </custom-exception-strategy>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-02
      • 2015-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-04
      • 1970-01-01
      • 2012-11-14
      相关资源
      最近更新 更多