Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Распределенная транзакция между удаленными службами REST, реализованная с помощью Spring Boot с использованием диспетчера транзакций Atomikos

Автор вопроса: zoranОтветов: 1

Мне нужны две службы REST, которые являются частью одной транзакции (распределенной транзакции), поэтому, если, например, клиент вызывает SERVICE_1, который был успешным, а затем SERVICE_2, который не был успешным, SERVICE_2 И SERVICE_1 должен выполнить откат.

Я успешно добился этого с помощью диспетчера транзакций Atomikos (TransactionEssentials), служб, реализованных с помощью Apache CXF, и клиента Java (оркестратор транзакций), который вызывает службы REST с помощью JAX-RS. Я основывал свою работу на отличных примерах, предоставленных Atomikos, которые можно найти здесь: https://www.atomikos.com/downloads/extreme-transactions/com/atomikos/examples/5.0.6/examples-5.0.6-project.zip (примеры-jta-rest-jaxrs).

Проблема, с которой я столкнулся, заключается в том, что когда я заменяю реализацию служб REST на Spring Boot, глобальная транзакция больше не работает. Я сузил проблему до службы Spring Boot REST, которая не возвращает атрибут Atomikos-Extent в заголовке, который требуется вызывающей стороне (которая начинает и фиксирует глобальную транзакцию). Это исключение, которое вызывает вызывающий абонент:

WARNING: Invalid extent found - any remote work will time out and rollback.
java.lang.IllegalArgumentException: Expected an extent but found none. The remote work will not be committed by us.
      at com.atomikos.remoting.DefaultExportingTransactionManager.addExtent(DefaultExportingTransactionManager.java:70)

Итак, вопрос в том, как реализовать службу Spring Boot REST, чтобы она могла участвовать в глобальных транзакциях с помощью диспетчера транзакций Atomikos.

Ниже приведены некоторые важные фрагменты кода.

Клиент / звонящий

Client client1= newClient().register(JacksonJsonProvider.class)
        .register(ParticipantsProvider.class)
        .register(TransactionAwareRestClientFilter.class);
Client client2 = //same as client1
UserTransactionManager utm = new UserTransactionManager();
utm.init();
utm.begin();
callService1();
callService2();
utm.commit();
utm.close();

Услуга

@EnableTransactionManagement
@SpringBootApplication
public class SpringBootAtomikosExampleApplication {
    //..
    @Bean(initMethod="init", destroyMethod="close")
    public AtomikosDataSourceBean dataSource() {
        AtomikosDataSourceBean ds = new AtomikosDataSourceBean();
        //..
        return ds;
    }
}

@Transactional
@RestController
public class MyController {

    @RequestMapping("/test")
    public void test() throws Exception {
        TransactionManager tm = new UserTransactionManager();
        tm.begin();
        try (Connection con = dataSource.getConnection();
            Statement s = con.createStatement();) {
            s.executeQuery("select count(*) from menu");
        }
        tm.commit();
    }
}

Я нашел расплывчатую информацию о том, что при весенней загрузке вы должны использовать Atomikos ExtremeTransaction вместо TransactionEssentials, но я не уверен, что это решение.

spring-bootrestjtadistributed-transactionsatomikos

Ответы

Ответ 1 · Ursache

Ты используешь

  • com.atomikos.remoting.spring.rest.TransactionAwareRestContainerFilter
  • com.atomikos.remoting.spring.rest.TransactionAwareRestClientInterceptor

классы?

TransactionAwareRestClientFilter находится в пакете jaxrs.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы