7

我有这个用例。

第一条链:

<int:chain input-channel="inserimentoCanaleActivate" output-channel="inserimentoCanalePreRouting">      
    <int:service-activator ref="inserimentoCanaleActivator" method="activate" />                
</int:chain>

这是相关代码:

@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public EventMessage<ModificaOperativitaRapporto> activate(EventMessage<InserimentoCanale> eventMessage) {
    ...
    // some Database changes
    dao.save(myObject);
}

一切都很好。

然后我有另一个链:

<int:chain id="onlineCensimentoClienteChain" input-channel="ONLINE_CENSIMENTO_CLIENTE" output-channel="inserimentoCanaleActivate">
    <int:service-activator ref="onlineCensimentoClienteActivator" method="activate" />
    <int:splitter expression="payload.getPayload().getCanali()" />
</int:chain>

和相对激活剂:

@Override
public EventMessage<CensimentoCliente> activate(EventMessage<CensimentoCliente> eventMessage) {
    ...
    // some Database changes
    dao.save(myObject);
}

CensimentoCliente如下所述的List有效负载具有第一个链的有效负载,因此我使用拆分器拆分列表并重用第一个链的代码。

public interface CensimentoCliente extends Serializable {

    Collection<? extends InserimentoCanale> getCanali();

    void setCanali(Collection<? extends InserimentoCanale> canali);
    ...
}

但是由于每个激活器都获得了他的事务定义(因为第一个激活器可以在没有第二个激活器的情况下存在)我有一个事务分离的用例。

目标是让两条链的数据库修改成为同一事务的一部分。

有什么帮助吗?

亲切的问候马西莫

4

3 回答 3

3

您可以通过创建自定义通道(或其他自定义组件,但这是最简单的方法)将消息调度包装在 TransactionTemplate 回调执行中来完成此操作:

public class TransactionalChannel extends AbstractSubscribableChannel {

    private final MessageDispatcher dispatcher = new UnicastingDispatcher();
    private final TransactionTemplate transactionTemplate;

    TransactionalChannel(TransactionTemplate transactionTemplate) {
        this.transactionTemplate = transactionTemplate;
    }

    @Override
    protected boolean doSend(final Message<?> message, long timeout) {
        return transactionTemplate.execute(new TransactionCallback<Boolean>() {
            @Override
            public Boolean doInTransaction(TransactionStatus status) {
                return getDispatcher().dispatch(message);
            }
        });
    }

    @Override
    protected MessageDispatcher getDispatcher() {
        return dispatcher;
    }

}

在您的 XML 中,您可以定义您的渠道和交易模板,并像引用任何其他渠道一样引用您的自定义渠道:

    <bean id="transactionalChannel" class="com.stackoverflow.TransactionalChannel">
        <constructor-arg>
           <bean class="org.springframework.transaction.support.TransactionTemplate">
              <property name="transactionManager" ref="transactionManager"/>
              <property name="propagationBehavior" value="#{T(org.springframework.transaction.TransactionDefinition).PROPAGATION_REQUIRES_NEW}"/>
          </bean>
       </constructor-arg>
    </bean>

对于您的示例,您也许可以使用桥接器通过新通道传递消息:

<int:bridge input-channel="inserimentoCanaleActivate" output-channel="transactionalChannel" /> 
<int:chain input-channel="transactionalChannel" output-channel="inserimentoCanalePreRouting">      
    <int:service-activator ref="inserimentoCanaleActivator" method="activate" />                
</int:chain>
于 2013-09-15T14:46:16.940 回答
3

您拥有<service-activator>服务@Transactional方法,事务将仅绑定到该方法调用。如果您想对整个消息流(或其部分)进行交易,您应该在之前的某个地方声明 TX 通知。如果您的通道是直接的,所有服务调用都将使用相同的事务进行包装。实现您的愿望的最简单方法,编写简单的@Gateway界面@Transactional并从您的消息流开始调用它。

澄清一下有关事务 的信息 了解消息流中的事务

于 2013-09-16T08:22:33.050 回答
0

这些是在修改 2 个独立的关系数据库吗?如果是这样,您正在查看 XA 事务。现在,如果您在像 tomcat 这样的非 XA 容器上运行它,所有这些都必须在由事务管理器监视的单个线程中完成 - (您将不得不捎带实际触发这些事件的事务管理器)。事务管理器可以是 JMS 消息或针对某些数据源的轮询器。此外,此处理必须在单个线程中完成,以便 spring 可以帮助您在单个事务中运行整个过程。

最后一点,不要在服务激活器之间引入线程池/队列。这可能导致激活器在单独的线程中运行

于 2013-07-30T07:25:12.327 回答