[英]Spring Integration: start new transaction in my Message flow IntegrationFlowBuilder to commit change and resume the outer transaction
My jdbcSourceMessage execute a select for update with batch of 100 rows at a time.我的 jdbcSourceMessage 执行 select 以一次更新 100 行。 While the integrationFlow is been executed in a Transaction to hold a lock to the database for the fetched batch.
在事务中执行集成流时,为获取的批次持有数据库锁。 I would like to start new Transaction for my JdbcSourceUpdate (within the message flow) to excute an update and commit my change for each row sent throught the channel.
我想为我的 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);
}
}
}
Since you have that JdbcSourceUpdate
implementation, there is just enough to do like this:既然你有那个
JdbcSourceUpdate
实现,那么这样做就足够了:
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void handleMessage(Message<?> message) throws MessagingException {
See its JavaDocs for more info:有关更多信息,请参阅其 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),
UPDATE更新
Pay attention to the NOTE though:请注意注意事项:
* 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}`.
So, sounds like DataSourceTransactionManager
doesn't work with suspension.因此,听起来
DataSourceTransactionManager
不适用于暂停。 I can suggest you to consider to use a .gateway()
for that JdbcSourceUpdate
, but using an ExecutorChannel
.我可以建议您考虑为该
JdbcSourceUpdate
使用.gateway()
,但使用ExecutorChannel
。 This way your handle(jdbcSourceUpdate()
will be performed on a new thread and, therefore, with a new transaction. The main flow will wait for the reply from that gateway holding its transaction opened.这样,您的
handle(jdbcSourceUpdate()
将在新线程上执行,因此将使用新事务。主要流程将等待来自保持其事务打开的网关的回复。
Something like this:像这样的东西:
.subscribe(f -> f
.gateway(subFlow ->
subFlow.channel(c -> c.executor())
.handle(jdbcMessageHandler()))
.channel("nullChannel")
));
Buy your JdbcSourceUpdate
must return something for the gateway reply.购买你的
JdbcSourceUpdate
必须为网关回复返回一些东西。 Consider do not implement MessageHandler
there, but make just as a plain POJO with a single non- void
method.考虑不要在那里实现
MessageHandler
,而是将其作为具有单个非void
方法的普通 POJO。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.