Mule ESB 3.3如何同时启动事务流

时间:2013-01-11 01:41:53

标签: asynchronous transactions esb mule

我想同时处理一组消息,但除非我将VM设置为请求 - 响应,否则我无法设法将它们转换为...在这种情况下,处理不是并发的。

Mule documentation表示“Mule事务在同步端点上配置”,但我不太明白这个限制。
很明显,在你想成为事务流的流中,不应该产生异步流,但是不清楚(对我来说)为什么一个人无法启动(从非tx主流)任何数量的异步流都是事务性的。

换句话说,为什么这样可行:

enter image description here

但如果我将VM更改为“单向”,则会失败并显示:

org.mule.transaction.IllegalTransactionStateException: Can only bind "javax.sql.DataSource/java.sql.Connection" type resources

有解决方法吗?

流程的XML:

<?xml version="1.0" encoding="UTF-8"?>
<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" />
        <set-payload value="#[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]" doc:name="[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]"/>
        <collection-splitter doc:name="Collection Splitter"/>
        <vm:outbound-endpoint exchange-pattern="request-response" path="flow" doc:name="flow" />
    </flow>

    <flow name="flow" doc:name="flow">
        <vm:inbound-endpoint exchange-pattern="request-response" path="flow" doc:name="flow">
            <custom-transaction factory-ref="transactionFactory" action="ALWAYS_BEGIN" timeout="10" />
        </vm:inbound-endpoint>
        <logger message="#[payload]" level="INFO" doc:name="Logger"/>
        <jdbc:outbound-endpoint exchange-pattern="request-response" queryKey="insert" queryTimeout="-1" connector-ref="dbConnector" doc:name="Insert 1">
            <jdbc:transaction action="ALWAYS_JOIN" />
            <jdbc:query key="insert" value="insert into test values (#[payload], 'Test 1')" />
        </jdbc:outbound-endpoint>
        <jdbc:outbound-endpoint exchange-pattern="request-response" queryKey="insert2" queryTimeout="-1" connector-ref="dbConnector" doc:name="Insert 2">
            <jdbc:transaction action="ALWAYS_JOIN" />
            <jdbc:query key="insert2" value="insert into test values (#[payload + 10], 'Test 2')" />
        </jdbc:outbound-endpoint>
    </flow>

</mule>

提前致谢。

3 个答案:

答案 0 :(得分:3)

  

Mule文档指出“Mule事务是在同步端点上配置的”,但我不太明白这个限制。

这个限制是由于,在Spring中的Mule中,更常见的是在Java中,事务是线程绑定的。对于异步流,涉及多个线程,因此无法维护事务线程关联。

所以不,你不能拆分/分叉/并行/异步处理消息,也可以在Mule中进行交易。

  

org.mule.transaction.IllegalTransactionStateException:只能绑定“javax.sql.DataSource / java.sql.Connection”类型的资源

但这与IMO的第一个问题无关:这是因为您强行通过custom-transaction尝试在JDBC事务中注册VM端点。这不行。如果要注册异构资源,请使用XA事务。

编辑:根据您在评论中所说的内容,您不希望在事务中注册VM端点,因此只需注册JDBC端点,如下所示:

<transactional action="ALWAYS_BEGIN">
    <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>
</transactional>

这适用于one-way入站端点。

答案 1 :(得分:1)

我设法让它发挥作用。我必须添加一个中间异步流,它会调用sync / tx流:

enter image description here

我认为这是丑陋和不必要的,并且将它作为原始帖子调用是完全可以的,但是出于超出我的原因,Mule会让你跳过这个箍。

以下是流程的XML:

<?xml version="1.0" encoding="UTF-8"?>
    <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" />
        <set-payload value="#[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]" doc:name="[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]"/>
        <collection-splitter doc:name="Collection Splitter"/>
        <vm:outbound-endpoint exchange-pattern="one-way" path="async" doc:name="async" />
    </flow>
    <flow name="simpletransactionFlow1" doc:name="simpletransactionFlow1">
        <vm:inbound-endpoint exchange-pattern="one-way" path="async" doc:name="async"/>
        <vm:outbound-endpoint exchange-pattern="request-response" path="flow" doc:name="flow"/>
    </flow>

    <flow name="flow" doc:name="flow">
        <vm:inbound-endpoint exchange-pattern="request-response" path="flow" doc:name="flow">
            <custom-transaction factory-ref="transactionFactory" action="ALWAYS_BEGIN" timeout="10" />
        </vm:inbound-endpoint>
        <logger message="#[groovy:Thread.currentThread().getName()], payload=#[payload]" level="INFO" doc:name="Logger"/>
        <jdbc:outbound-endpoint exchange-pattern="request-response" queryKey="insert" queryTimeout="-1" connector-ref="dbConnector" doc:name="Insert 1">
            <jdbc:transaction action="ALWAYS_JOIN" />
            <jdbc:query key="insert" value="insert into test values (#[payload], 'Test 1')" />
        </jdbc:outbound-endpoint>
        <jdbc:outbound-endpoint exchange-pattern="request-response" queryKey="insert2" queryTimeout="-1" connector-ref="dbConnector" doc:name="Insert 2">
            <jdbc:transaction action="ALWAYS_JOIN" />
            <jdbc:query key="insert2" value="insert into test values (#[payload + 10], 'Test 2')" />
        </jdbc:outbound-endpoint>
    </flow>

</mule>

答案 2 :(得分:0)

这在Mule documentation中讨论。它可能需要更加繁琐,但它并不太糟糕,实际上只需要一个VM Transport,而不是两个:

enter image description here

我改变它是因为我想使用TCP而不是HTTP,但它基本上是相同的例子。

第一个流接收未经过处理的TCP,对它做了一些事情(这里只是一个Byte Array To String,但可能你有验证或其他东西),将输入推送到VM Connector,然后将输入回送到TCP流。在VM Connector保证TCP源可以放弃其消息之后返回,如果它正在进行一些低级保证传送。

VM Connector是单向的,并且连接了持久性存储,因此它不会丢失消息。这在Mule Studio 3.5中显示错误,但它工作正常。

然后中间流接管并包含一个事务,因此除非业务逻辑子流成功完成,否则VM Connector不会放弃该消息。

最后子流程运行;目前只是Thread.sleep()持续5秒,所以我可以看到它全部正常工作。 Telnet in有一个瞬间回显给Telnet控制台,然后五秒后又回到另一个回声。

希望有所帮助!我只和Mule花了几个小时,但这似乎是正确的。