Распределенная транзакция по удаленным REST-сервисам, реализованная с помощью Spring Boot с помощью диспетчера транзакций Atomikos - PullRequest
0 голосов
/ 06 февраля 2020

Мне нужны две службы REST, которые являются частью одной транзакции (распределенной транзакции), поэтому, если, например, клиент вызывает SERVICE_1, который успешен, а затем SERVICE_2, который не успешен, SERVICE_2 AND 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 (examples-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, но я не уверен, что это решение.

1 Ответ

0 голосов
/ 21 февраля 2020

Используете ли вы

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

классы?

TransactionAwareRestClientFilter под Jaxrs пакет.

...