繁体   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