簡體   English   中英

Spring 集成:在我的消息流 IntegrationFlowBuilder 中啟動新事務以提交更改並恢復外部事務

[英]Spring Integration: start new transaction in my Message flow IntegrationFlowBuilder to commit change and resume the outer transaction

我的 jdbcSourceMessage 執行 select 以一次更新 100 行。 在事務中執行集成流時,為獲取的批次持有數據庫鎖。 我想為我的 JdbcSourceUpdate (在消息流中)啟動新事務以執行更新並為通過通道發送的每一行提交我的更改。

@Bean
public IntegrationFlow integrationFlow() {
    IntegrationFlowBuilder flowBuilder = IntegrationFlows.from(jdbcSourceMessage());
    flowBuilder
            .split()
            .log(LoggingHandler.Level.INFO, message ->
                    message.getHeaders().get("sequenceNumber")
                            + " événements publiés sur le bus de message sur "
                            + message.getHeaders().get("sequenceSize")
                            + " événements lus (lot)")
            .transform(Transformers.toJson())
            .log()
            .enrichHeaders(h -> h.headerExpression("type", "payload.typ_evenement"))
            .publishSubscribeChannel(publishSubscribeSpec -> publishSubscribeSpec
            .subscribe(flow -> flow
                    .bridge()
                    .transform(Transformers.toJson())
                    .transform(kafkaGuyTransformer())
                    .channel(this.rabbitMQchannel.demandeInscriptionOutput())) 
            .subscribe(flow -> flow
                    .handle(jdbcMessageHandler())) 
    );
    return flowBuilder.get();
}


@Bean(name = PollerMetadata.DEFAULT_POLLER)
public PollerMetadata defaultPoller() {
    PeriodicTrigger trigger = new PeriodicTrigger(this.proprietesSourceJdbc.getTriggerDelay(), TimeUnit.SECONDS);
    PollerMetadata pollerMetadata = Pollers.trigger(trigger)
            .advice(transactionInterceptor())
            .get();
    pollerMetadata.setMaxMessagesPerPoll(proprietesSourceJdbc.getMaxRowsPerPoll());
    return pollerMetadata;
}

@Bean
public JdbcSourceUpdate jdbcSourceUpdate() {
    return new JdbcSourceUpdate();
}

public TransactionInterceptor transactionInterceptor() {
    return new TransactionInterceptorBuilder()
            .transactionManager(transactionManager())
            .build();
}

public PlatformTransactionManager transactionManager(){
    DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(sourceDeDonnees);
    transactionManager.setRollbackOnCommitFailure(false);
    return transactionManager;
}


public class KafkaGuyTransformer implements GenericTransformer<Message, Message> {

    @Override
    public Message transform(Message message) {
        Message<String> msg = null;
        try {
            DemandeRecueDTO dto = objectMapper.readValue(message.getPayload().toString(), DemandeRecueDTO.class);
            msg = MessageBuilder.withPayload(dto.getTxtDonnee())
                    .copyHeaders(message.getHeaders())
                    .build();
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
        }
        return msg;
    }
}

public class JdbcSourceUpdate implements MessageHandler {
    @Override
    public void handleMessage(Message<?> message) throws MessagingException {
        try {
            Thread.sleep(100);
            DemandeRecueDTO dto = objectMapper.readValue(message.getPayload().toString(), DemandeRecueDTO.class);
            jdbcTemplate.update(proprietesSourceJdbc.getUpdate(), dto.getIdEvenementDemandeCrcd());
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
        }
    }
}

既然你有那個JdbcSourceUpdate實現,那么這樣做就足夠了:

@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void handleMessage(Message<?> message) throws MessagingException {

有關更多信息,請參閱其 JavaDocs:

/**
 * Create a new transaction, and suspend the current transaction if one exists.
 * Analogous to the EJB transaction attribute of the same name.
 * <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
 * on all transaction managers. This in particular applies to
 * {@link org.springframework.transaction.jta.JtaTransactionManager},
 * which requires the {@code javax.transaction.TransactionManager} to be
 * made available to it (which is server-specific in standard Java EE).
 * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
 */
REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),

更新

請注意注意事項:

 * Actual transaction suspension will not work out-of-the-box
 * on all transaction managers. This in particular applies to
 * {@link org.springframework.transaction.jta.JtaTransactionManager}`. 

因此,聽起來DataSourceTransactionManager不適用於暫停。 我可以建議您考慮為該JdbcSourceUpdate使用.gateway() ,但使用ExecutorChannel 這樣,您的handle(jdbcSourceUpdate()將在新線程上執行,因此將使用新事務。主要流程將等待來自保持其事務打開的網關的回復。

像這樣的東西:

                        .subscribe(f -> f
                                .gateway(subFlow ->
                                        subFlow.channel(c -> c.executor())
                                                .handle(jdbcMessageHandler()))
                                .channel("nullChannel")
                        ));

購買你的JdbcSourceUpdate必須為網關回復返回一些東西。 考慮不要在那里實現MessageHandler ,而是將其作為具有單個非void方法的普通 POJO。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM