Spring Integration - откат второй транзакции, если первая транзакция не удалась - PullRequest
0 голосов
/ 04 сентября 2018

Я должен сохранить данные в 2 разных таблицах. Мне нужно, чтобы это была сделка "все или ничего". Как откатить первую транзакцию, если вторая транзакция не удалась?

В приведенном ниже коде я storeToTable1 (), storeToTable2 () выполняется в этом порядке.

Я хочу, чтобы storeToTable1 () выполнял откат в случае сбоя storeToTable2 ().

Класс конфигурации:

class StoreToDBConfig {
    @Bean
        public IntegrationFlow receiveMessage() {
            return IntegrationFlows
                    .from("inputChannel")
                    .transform("convertToTable1Format")
                    .handle(ServicetoDBAdaptor,"storeToTable1")
                    .transform("convertToTable2Format")
                    .handle(ServicetoDBAdaptor,"storeToTable2")
                    .get();                 
        }
}

Адаптер для обслуживания БД:

class ServicetoDBAdaptor {

@Autowired
UserExecutionDetail userExecutionDetail;

@Autowired
UserExecution userExecution;

@Autowired
UserExecutionDetailRepository userExecutionDetailRepository;

@Autowired
UserExecutionRepository userExecutionRepository;

@Transactional(propagation=Propagation.REQUIRED)
@ServiceActivator
private void storeToTable1(Message<UserExecutionDetail> msg) throws Exception {
    userExecutionDetailRepository.save(msg.getPayload());
}

@Transactional(propagation=Propagation.REQUIRED)
@ServiceActivator
private void storeToTable2(Message<UserExecution> msg) throws Exception {
    userExecutionRepository.save(msg.getPayload());
}
}

1 Ответ

0 голосов
/ 04 сентября 2018

Для этого вам нужно использовать на первом handle() что-то вроде этого:

.handle(ServicetoDBAdaptor,"storeToTable1", e -> e.transactional(true))

Этот хук будет делать именно это:

/**
 * Specify a {@link TransactionInterceptor} {@link Advice} with default
 * {@code PlatformTransactionManager} and {@link DefaultTransactionAttribute} for the
 * {@link MessageHandler}.
 * @param handleMessageAdvice the flag to indicate the target {@link Advice} type:
 * {@code false} - regular {@link TransactionInterceptor}; {@code true} -
 * {@link org.springframework.integration.transaction.TransactionHandleMessageAdvice}
 * extension.
 * @return the spec.
 */
public S transactional(boolean handleMessageAdvice) {

Где мы собираемся использовать это:

/**
 * A {@link TransactionInterceptor} extension with {@link HandleMessageAdvice} marker.
 * <p>
 * When this {@link Advice} is used from the {@code request-handler-advice-chain}, it is applied
 * to the {@link MessageHandler#handleMessage}
 * (not to the
 * {@link org.springframework.integration.handler.AbstractReplyProducingMessageHandler.RequestHandler#handleRequestMessage}),
 * therefore the entire downstream process is wrapped to the transaction.
 * <p>
 * In any other cases it is operated as a regular {@link TransactionInterceptor}.
 *
 * @author Artem Bilan
 *
 * @since 5.0
 */
@SuppressWarnings("serial")
public class TransactionHandleMessageAdvice extends TransactionInterceptor implements HandleMessageAdvice {

Ключевой трюк здесь the entire downstream process is wrapped to the transaction..

Поэтому транзакция начнется с вашего storeToTable1() и будет расширена до конца потока, и ваш storeToTable2() будет участвовать в той же передаче. Таким образом, когда этот откатывается, первый тоже будет откатываться. Только потому, что у вас будет только одна транзакция!

...