Мне нужны две службы 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, но я не уверен, что это решение.