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);
    ...
}

しかし、すべてのアクティベーターがトランザクション定義を取得するため (最初のアクティベーターは 2 番目のアクティベーターなしで存続できるため)、トランザクションが分離されているユースケースがあります。

目標は、2 つのチェーンのデータベース変更を同じトランザクションの一部にすることです。

何か助けはありますか?

よろしくマッシモ

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 に答える
0

これらは 2 つの別々のリレーショナル データベースを変更していますか? そうであれば、XA トランザクションを見ています。これを tomcat のような非 XA コンテナーで実行する場合、トランザクション マネージャーが監視する単一のスレッドでこれらすべてを実行する必要があります (これらのイベントを実際にトリガーするトランザクション マネージャーに便乗する必要があります)。トランザクション マネージャーは、JMS メッセージまたは一部のデータ ソースに対するポーラーにすることができます。また、Spring がプロセス全体を単一のトランザクションで実行できるように、この処理は単一のスレッドで実行する必要があります。

最後に、サービスアクティベーター間にスレッドプール/キューを導入しないでください。これにより、アクティベーターが別のスレッドで実行される可能性があります

于 2013-07-30T07:25:12.327 に答える