1. Введение
Atomikos — это библиотека транзакций для Java-приложений . В этом уроке мы поймем, почему и как использовать Atomikos.
В процессе мы также рассмотрим основы транзакций и то, зачем они нам нужны.
Затем мы создадим простое приложение с транзакциями, использующими различные API от Atomikos.
2. Понимание основ
Прежде чем мы обсудим Atomikos, давайте разберемся, что такое транзакции, и несколько связанных с ними понятий. Проще говоря, транзакция — это логическая единица работы, эффект которой виден вне транзакции либо полностью, либо не виден совсем .
Давайте возьмем пример, чтобы понять это лучше. Типичное розничное приложение резервирует запасы, а затем размещает заказ:
Здесь мы хотели бы, чтобы эти две операции либо происходили вместе, либо не происходили вообще. Мы можем добиться этого, объединив эти операции в одну транзакцию.
2.1. Локальная и распределенная транзакция
Транзакция может включать несколько независимых операций. Эти операции могут выполняться на одном и том же ресурсе или на разных ресурсах . Здесь мы ссылаемся на участвующие в транзакции компоненты, такие как база данных, как на ресурс.
Транзакции внутри одного ресурса называются локальными транзакциями, а транзакции, порождаемые несколькими ресурсами, называются распределенными транзакциями:
Здесь инвентаризация и заказы могут быть двумя таблицами в одной базе данных или двумя разными базами данных, которые могут работать на разных машинах.
2.2. Спецификация XA и API транзакций Java
XA относится к расширенной архитектуре , которая является спецификацией распределенной обработки транзакций. Цель XA — обеспечить атомарность глобальных транзакций с участием разнородных компонентов .
Спецификация XA обеспечивает целостность с помощью протокола, известного как двухфазная фиксация. Двухфазная фиксация — это широко используемый распределенный алгоритм, облегчающий принятие решения о фиксации или откате распределенной транзакции.
Java Transaction API (JTA) — это API Java Enterprise Edition, разработанный в рамках Java Community Process. Он позволяет Java-приложениям и серверам приложений выполнять распределенные транзакции по ресурсам XA .
JTA смоделирован на основе архитектуры XA с использованием двухэтапной фиксации. JTA определяет стандартные интерфейсы Java между менеджером транзакций и другими сторонами распределенной транзакции.
3. Введение в Атомикос
Теперь, когда мы ознакомились с основами транзакций, мы готовы изучить Atomikos. В этом разделе мы поймем, что такое Atomikos и как он связан с такими понятиями, как XA и JTA. Мы также поймем архитектуру Atomikos и рассмотрим предлагаемые ею продукты.
3.1. Что такое атомикос
Как мы видели, JTA предоставляет интерфейсы на языке Java для создания приложений с распределенными транзакциями. Теперь JTA — это просто спецификация и не предлагает никакой реализации. Чтобы запустить приложение, в котором мы используем JTA, нам нужна реализация JTA . Такая реализация называется менеджером транзакций.
Как правило, сервер приложений предоставляет реализацию диспетчера транзакций по умолчанию. Например, в случае Enterprise Java Beans (EJB) контейнеры EJB управляют поведением транзакций без какого-либо явного вмешательства разработчиков приложений. Однако во многих случаях это может быть не идеально, и нам может понадобиться прямой контроль над транзакцией, независимый от сервера приложений.
Atomikos — это облегченный менеджер транзакций для Java , который позволяет приложениям, использующим распределенные транзакции, быть автономными. По сути, нашему приложению не нужно полагаться на такой тяжеловесный компонент, как сервер приложений для транзакций. Это приближает концепцию распределенных транзакций к облачной архитектуре.
3.2. Атомикос Архитектура
Atomikos изначально создавался как менеджер транзакций JTA и, следовательно, реализует архитектуру XA с протоколом двухфазной фиксации . Давайте посмотрим на высокоуровневую архитектуру с Atomikos:
Здесь Atomikos упрощает транзакцию на основе двухэтапной фиксации, охватывающую базу данных и очередь сообщений.
3.3. Предложения продуктов Атомикос
Atomikos — это менеджер распределенных транзакций, который предлагает больше возможностей, чем требует JTA/XA. У него есть продукт с открытым исходным кодом и гораздо более полное коммерческое предложение:
- TransactionsEssentials: продукт Atomikos с открытым исходным кодом, предоставляющий менеджер транзакций JTA/XA для приложений Java, работающих с базами данных и очередями сообщений. Это в основном полезно для целей тестирования и оценки.
- ExtremeTransactions: коммерческое предложение Atomikos, которое предлагает распределенные транзакции в составных приложениях, включая службы REST, помимо баз данных и очередей сообщений. Это полезно для создания приложений, выполняющих экстремальную обработку транзакций (XTP).
В этом руководстве мы будем использовать библиотеку TransactionsEssentials для создания и демонстрации возможностей Atomikos.
4. Настройка Атомикоса
Как мы видели ранее, одним из основных преимуществ Atomikos является то, что это встроенный сервис транзакций . Это означает, что мы можем запустить его в той же JVM, что и наше приложение. Таким образом, настроить Atomikos довольно просто.
4.1. Зависимости
Во-первых, нам нужно настроить зависимости. Здесь все, что нам нужно сделать, это объявить зависимости в нашем файле Maven pom.xml
:
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jdbc</artifactId>
<version>5.0.6</version>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jms</artifactId>
<version>5.0.6</version>
</dependency>
В этом случае мы используем зависимости Atomikos для JDBC и JMS , но аналогичные зависимости доступны в Maven Central для других ресурсов жалоб XA.
4.2. Конфигурации
Atomikos предоставляет несколько параметров конфигурации с разумными значениями по умолчанию для каждого из них. Самый простой способ переопределить эти параметры — указать файл transaction.properties
в пути к классам . Мы можем добавить несколько параметров для инициализации и работы службы транзакций. Давайте рассмотрим простую конфигурацию для переопределения каталога, в котором создаются файлы журнала:
com.atomikos.icatch.file=path_to_your_file
Точно так же есть и другие параметры, которые мы можем использовать для управления временем ожидания транзакций, установки уникальных имен для нашего приложения или определения поведения при завершении работы.
4.3. Базы данных
В нашем руководстве мы создадим простое приложение для розничной торговли, подобное описанному ранее, которое резервирует запасы, а затем размещает заказ. Мы будем использовать реляционную базу данных для простоты. Кроме того, мы будем использовать несколько баз данных для демонстрации распределенных транзакций. Однако это вполне может распространяться и на другие ресурсы XA-жалоб, такие как очереди сообщений и темы .
Наша база данных инвентаризации будет иметь простую таблицу для размещения инвентаризации продуктов:
CREATE TABLE INVENTORY (
productId VARCHAR PRIMARY KEY,
balance INT
);
И наша база данных заказов будет иметь простую таблицу для размещения размещенных заказов:
CREATE TABLE ORDERS (
orderId VARCHAR PRIMARY KEY,
productId VARCHAR,
amount INT NOT NULL CHECK (amount <= 5)
);
Это очень простая схема базы данных, полезная только для демонстрации. Однако важно отметить, что ограничение нашей схемы не допускает заказа с количеством продуктов более пяти.
5. Работа с атомикосом
Теперь мы готовы использовать одну из библиотек Atomikos для создания нашего приложения с распределенными транзакциями. В следующих подразделах мы будем использовать встроенные адаптеры ресурсов Atomikos для подключения к нашим внутренним системам баз данных. Это самый быстрый и простой способ начать работу с Atomikos .
5.1. Создание экземпляра UserTransaction
Мы будем использовать JTA UserTransaction
для разграничения границ транзакций. Все остальные шаги, связанные с обслуживанием транзакций, будут выполнены автоматически . Это включает в себя зачисление и удаление ресурсов из списка с помощью службы транзакций.
Во-первых, нам нужно создать экземпляр UserTransaction
из Atomikos:
UserTransactionImp utx = new UserTransactionImp();
5.2. Создание источника данных
Затем нам нужно создать экземпляр DataSource
из Atomikos. Atomikos предоставляет две версии DataSource
.
Первый, AtomikosDataSourceBean
, знает о базовом XADataSource
:
AtomikosDataSourceBean dataSource = new AtomikosDataSourceBean();
Хотя AtomikosNonXADataSourceBean
использует любой обычный класс драйвера JDBC:
AtomikosNonXADataSourceBean dataSource = new AtomikosNonXADataSourceBean();
Как следует из названия, AtomikosNonXADataSource
не совместим с XA. Следовательно, нельзя гарантировать атомарность транзакций, выполняемых с таким источником данных. Так зачем нам это использовать? У нас может быть какая-то база данных, которая не поддерживает спецификацию XA. Atomikos не запрещает нам использовать такой источник данных и все же пытается обеспечить атомарность, если в транзакции есть единственный такой источник данных. Этот метод похож на Last Resource Gambit, вариант двухэтапного процесса фиксации.
Кроме того, нам необходимо соответствующим образом настроить DataSource
в зависимости от базы данных и драйвера.
5.3. Выполнение операций с базой данных
После настройки довольно легко использовать DataSource
в контексте транзакции в нашем приложении:
public void placeOrder(String productId, int amount) throws Exception {
String orderId = UUID.randomUUID().toString();
boolean rollback = false;
try {
utx.begin();
Connection inventoryConnection = inventoryDataSource.getConnection();
Connection orderConnection = orderDataSource.getConnection();
Statement s1 = inventoryConnection.createStatement();
String q1 = "update Inventory set balance = balance - " + amount + " where productId ='" +
productId + "'";
s1.executeUpdate(q1);
s1.close();
Statement s2 = orderConnection.createStatement();
String q2 = "insert into Orders values ( '" + orderId + "', '" + productId + "', " + amount + " )";
s2.executeUpdate(q2);
s2.close();
inventoryConnection.close();
orderConnection.close();
} catch (Exception e) {
rollback = true;
} finally {
if (!rollback)
utx.commit();
else
utx.rollback();
}
}
Здесь мы обновляем таблицы базы данных для запасов и заказов в пределах границ транзакции. Это автоматически обеспечивает преимущество этих операций, происходящих атомарно.
5.4. Тестирование транзакционного поведения
Наконец, мы должны иметь возможность протестировать наше приложение с помощью простых модульных тестов, чтобы убедиться, что поведение транзакции соответствует ожидаемому:
@Test
public void testPlaceOrderSuccess() throws Exception {
int amount = 1;
long initialBalance = getBalance(inventoryDataSource, productId);
Application application = new Application(inventoryDataSource, orderDataSource);
application.placeOrder(productId, amount);
long finalBalance = getBalance(inventoryDataSource, productId);
assertEquals(initialBalance - amount, finalBalance);
}
@Test
public void testPlaceOrderFailure() throws Exception {
int amount = 10;
long initialBalance = getBalance(inventoryDataSource, productId);
Application application = new Application(inventoryDataSource, orderDataSource);
application.placeOrder(productId, amount);
long finalBalance = getBalance(inventoryDataSource, productId);
assertEquals(initialBalance, finalBalance);
}
Здесь мы ожидаем, что действительный заказ уменьшит запасы, а недействительный заказ оставит запасы без изменений . Обратите внимание, что в соответствии с ограничением нашей базы данных любой заказ с количеством более пяти единиц товара считается недействительным.
5.5. Расширенное использование атомикоса
Приведенный выше пример является самым простым способом использования Atomikos и, возможно, достаточен для большинства требований. Однако есть и другие способы использования Atomikos для создания нашего приложения. Хотя некоторые из этих опций упрощают использование Atomikos, другие обеспечивают большую гибкость. Выбор зависит от наших требований.
Конечно, нет необходимости всегда использовать адаптеры Atomikos для JDBC/JMS . Мы можем выбрать использование диспетчера транзакций Atomikos при работе напрямую с XAResource
. Однако в этом случае мы должны явно позаботиться о включении и исключении из списка экземпляров XAResource
с помощью службы транзакций.
Atomikos также позволяет использовать более продвинутые функции через проприетарный интерфейс UserTransactionService
. Используя этот интерфейс, мы можем явно зарегистрировать ресурсы для восстановления. Это дает нам детальный контроль над тем, какие ресурсы должны быть восстановлены, как они должны быть восстановлены и когда должно произойти восстановление.
6. Интеграция Атомикос
Хотя Atomikos обеспечивает отличную поддержку распределенных транзакций, работать с такими низкоуровневыми API не всегда удобно. Чтобы сосредоточиться на бизнес-области и избежать беспорядка стандартного кода, нам часто требуется поддержка различных фреймворков и библиотек. Atomikos поддерживает большинство популярных фреймворков Java, связанных с внутренней интеграцией. Мы рассмотрим пару из них здесь.
6.1. Атомикос с Spring и DataSource
Spring — одна из популярных платформ на Java, предоставляющая контейнер Inversion of Control (IoC). Примечательно, что он также имеет фантастическую поддержку транзакций. Он предлагает декларативное управление транзакциями с использованием методов аспектно-ориентированного программирования (АОП).
Spring поддерживает несколько API транзакций, включая JTA для распределенных транзакций. Мы можем без особых усилий использовать Atomikos в качестве менеджера транзакций JTA в Spring . Самое главное, благодаря Spring наше приложение практически не зависит от Atomikos.
Давайте посмотрим, как мы можем решить нашу предыдущую проблему, на этот раз используя Spring. Мы начнем с переписывания класса Application :
public class Application {
private DataSource inventoryDataSource;
private DataSource orderDataSource;
public Application(DataSource inventoryDataSource, DataSource orderDataSource) {
this.inventoryDataSource = inventoryDataSource;
this.orderDataSource = orderDataSource;
}
@Transactional(rollbackFor = Exception.class)
public void placeOrder(String productId, int amount) throws Exception {
String orderId = UUID.randomUUID().toString();
Connection inventoryConnection = inventoryDataSource.getConnection();
Connection orderConnection = orderDataSource.getConnection();
Statement s1 = inventoryConnection.createStatement();
String q1 = "update Inventory set balance = balance - " + amount + " where productId ='" +
productId + "'";
s1.executeUpdate(q1);
s1.close();
Statement s2 = orderConnection.createStatement();
String q2 = "insert into Orders values ( '" + orderId + "', '" + productId + "', " + amount + " )";
s2.executeUpdate(q2);
s2.close();
inventoryConnection.close();
orderConnection.close();
}
}
Как мы видим здесь, большая часть шаблонного кода, связанного с транзакциями, была заменена одной аннотацией на уровне метода. Более того, Spring позаботится о создании и внедрении DataSource,
от которого зависит наше приложение.
Конечно, мы должны предоставить соответствующие конфигурации для Spring. Мы можем использовать простой класс Java для настройки этих элементов:
@Configuration
@EnableTransactionManagement
public class Config {
@Bean(initMethod = "init", destroyMethod = "close")
public AtomikosDataSourceBean inventoryDataSource() {
AtomikosDataSourceBean dataSource = new AtomikosDataSourceBean();
// Configure database holding order data
return dataSource;
}
@Bean(initMethod = "init", destroyMethod = "close")
public AtomikosDataSourceBean orderDataSource() {
AtomikosDataSourceBean dataSource = new AtomikosDataSourceBean();
// Configure database holding order data
return dataSource;
}
@Bean(initMethod = "init", destroyMethod = "close")
public UserTransactionManager userTransactionManager() throws SystemException {
UserTransactionManager userTransactionManager = new UserTransactionManager();
userTransactionManager.setTransactionTimeout(300);
userTransactionManager.setForceShutdown(true);
return userTransactionManager;
}
@Bean
public JtaTransactionManager jtaTransactionManager() throws SystemException {
JtaTransactionManager jtaTransactionManager = new JtaTransactionManager();
jtaTransactionManager.setTransactionManager(userTransactionManager());
jtaTransactionManager.setUserTransaction(userTransactionManager());
return jtaTransactionManager;
}
@Bean
public Application application() {
return new Application(inventoryDataSource(), orderDataSource());
}
}
Здесь мы настраиваем AtomikosDataSourceBean
для двух разных баз данных, содержащих наши данные о запасах и заказах. Кроме того, мы также предоставляем необходимую конфигурацию для менеджера транзакций JTA.
Теперь мы можем протестировать наше приложение на транзакционное поведение, как и раньше. Опять же, мы должны проверить, что действительный заказ уменьшает наш баланс запасов, а недействительный заказ оставляет его без изменений.
6.2. Атомикос с Spring, JPA и Hibernate
Хотя Spring помог нам в определенной степени сократить шаблонный код, он по-прежнему довольно многословен. Некоторые инструменты могут сделать работу с реляционными базами данных в Java еще проще. Java Persistence API (JPA) — это спецификация, описывающая управление реляционными данными в приложениях Java. Это в значительной степени упрощает доступ к данным и код манипулирования ими.
Hibernate — одна из самых популярных реализаций спецификации JPA. Atomikos отлично поддерживает несколько реализаций JPA , включая Hibernate. Как и прежде, благодаря Spring и JPA наше приложение не зависит от Atomikos и Hibernate!
Давайте посмотрим, как Spring, JPA и Hibernate могут сделать наше приложение еще более лаконичным, предоставляя при этом преимущества распределенных транзакций через Atomikos . Как и прежде, мы начнем с переписывания класса Application :
public class Application {
@Autowired
private InventoryRepository inventoryRepository;
@Autowired
private OrderRepository orderRepository;
@Transactional(rollbackFor = Exception.class)
public void placeOrder(String productId, int amount) throws SQLException {
String orderId = UUID.randomUUID().toString();
Inventory inventory = inventoryRepository.findOne(productId);
inventory.setBalance(inventory.getBalance() - amount);
inventoryRepository.save(inventory);
Order order = new Order();
order.setOrderId(orderId);
order.setProductId(productId);
order.setAmount(new Long(amount));
orderRepository.save(order);
}
}
Как мы видим, сейчас мы не имеем дело с какими-либо низкоуровневыми API баз данных. Однако, чтобы эта магия работала, нам нужно настроить классы и конфигурации Spring Data JPA. Мы начнем с определения наших объектов домена:
@Entity
@Table(name = "INVENTORY")
public class Inventory {
@Id
private String productId;
private Long balance;
// Getters and Setters
}
@Entity
@Table(name = "ORDERS")
public class Order {
@Id
private String orderId;
private String productId;
@Max(5)
private Long amount;
// Getters and Setters
}
Далее нам нужно предоставить репозитории для этих сущностей:
@Repository
public interface InventoryRepository extends JpaRepository<Inventory, String> {
}
@Repository
public interface OrderRepository extends JpaRepository<Order, String> {
}
Это довольно простые интерфейсы, и Spring Data позаботится об их разработке с помощью реального кода для работы с объектами базы данных.
Наконец, нам нужно предоставить соответствующие конфигурации для источника данных как для баз данных запасов и заказов, так и для менеджера транзакций:
@Configuration
@EnableJpaRepositories(basePackages = "com.foreach.atomikos.spring.jpa.inventory",
entityManagerFactoryRef = "inventoryEntityManager", transactionManagerRef = "transactionManager")
public class InventoryConfig {
@Bean(initMethod = "init", destroyMethod = "close")
public AtomikosDataSourceBean inventoryDataSource() {
AtomikosDataSourceBean dataSource = new AtomikosDataSourceBean();
// Configure the data source
return dataSource;
}
@Bean
public EntityManagerFactory inventoryEntityManager() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
// Configure the entity manager factory
return factory.getObject();
}
}
@Configuration
@EnableJpaRepositories(basePackages = "com.foreach.atomikos.spring.jpa.order",
entityManagerFactoryRef = "orderEntityManager", transactionManagerRef = "transactionManager")
public class OrderConfig {
@Bean(initMethod = "init", destroyMethod = "close")
public AtomikosDataSourceBean orderDataSource() {
AtomikosDataSourceBean dataSource = new AtomikosDataSourceBean();
// Configure the data source
return dataSource;
}
@Bean
public EntityManagerFactory orderEntityManager() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
// Configure the entity manager factory
return factory.getObject();
}
}
@Configuration
@EnableTransactionManagement
public class Config {
@Bean(initMethod = "init", destroyMethod = "close")
public UserTransactionManager userTransactionManager() throws SystemException {
UserTransactionManager userTransactionManager = new UserTransactionManager();
userTransactionManager.setTransactionTimeout(300);
userTransactionManager.setForceShutdown(true);
return userTransactionManager;
}
@Bean
public JtaTransactionManager transactionManager() throws SystemException {
JtaTransactionManager jtaTransactionManager = new JtaTransactionManager();
jtaTransactionManager.setTransactionManager(userTransactionManager());
jtaTransactionManager.setUserTransaction(userTransactionManager());
return jtaTransactionManager;
}
@Bean
public Application application() {
return new Application();
}
}
Это все еще довольно много настроек, которые нам нужно сделать. Отчасти это связано с тем, что мы настраиваем Spring JPA для двух отдельных баз данных. Кроме того, мы можем дополнительно уменьшить эти конфигурации с помощью Spring Boot , но это выходит за рамки этого руководства.
Как и прежде, мы можем протестировать наше приложение на предмет того же транзакционного поведения. На этот раз ничего нового, за исключением того факта, что теперь мы используем Spring Data JPA с Hibernate.
7. Атомикос за пределами JTA
Хотя JTA обеспечивает превосходную поддержку транзакций для распределенных систем, эти системы должны быть совместимы с XA, как и большинство реляционных баз данных или очередей сообщений. Однако JTA бесполезен, если одна из этих систем не поддерживает спецификацию XA для протокола двухфазной фиксации. В эту категорию попадают несколько ресурсов, особенно в архитектуре микросервисов.
Несколько альтернативных протоколов поддерживают распределенные транзакции. Одним из них является вариант протокола двухфазной фиксации, в котором используются компенсации . Такие транзакции имеют ослабленную гарантию изоляции и известны как транзакции на основе компенсации. Участники совершают отдельные части транзакции в самой первой фазе, предлагая обработчик компенсации за возможный откат на второй фазе.
Существует несколько шаблонов проектирования и алгоритмов для реализации транзакции на основе компенсации. Например, Sagas — один из таких популярных шаблонов проектирования. Однако они обычно сложны в реализации и подвержены ошибкам.
Atomikos предлагает вариант компенсационной транзакции под названием Try-Confirm/Cancel (TCC) . TCC предлагает лучшую бизнес-семантику объектам транзакции. Однако это возможно только при поддержке расширенной архитектуры со стороны участников, а TCC доступен только в рамках коммерческого предложения Atomikos ExtremeTransactions.
8. Альтернативы Атомикосу
Мы прошли достаточно через Атомикос, чтобы оценить то, что он может предложить. Кроме того, есть коммерческое предложение от Atomikos с еще более мощными функциями. Однако Atomikos — не единственный вариант, когда дело доходит до выбора JTA-менеджера транзакций. Есть несколько других надежных вариантов на выбор. Посмотрим, как они поведут себя против Атомикоса.
8.1. Нараяна
Narayana , возможно, является одним из старейших менеджеров распределенных транзакций с открытым исходным кодом и в настоящее время управляется Red Hat. Он широко использовался в отрасли, развивался благодаря поддержке сообщества и повлиял на несколько спецификаций и стандартов.
Narayana обеспечивает поддержку широкого спектра протоколов транзакций, таких как JTA, JTS, веб-сервисы и REST, и это лишь некоторые из них. Кроме того, Нараяна может быть встроена в самые разные контейнеры.
По сравнению с Atomikos, Narayana предоставляет практически все функции диспетчера распределенных транзакций. Во многих случаях Narayana более гибок для интеграции и использования в приложениях. Например, у Нараяны есть языковые привязки как для C/C++, так и для Java. Однако это происходит за счет дополнительной сложности, и Atomikos сравнительно проще в настройке и использовании.
8.2. Битроникс
Bitronix — это полностью работающий менеджер транзакций XA, предоставляющий все услуги, требуемые JTA API . Важно отметить, что Bitronix — это встраиваемая библиотека транзакций, которая предоставляет обширные и полезные отчеты об ошибках и ведение журналов. Для распределенной транзакции это упрощает исследование сбоев. Более того, он отлично поддерживает транзакционные возможности Spring и работает с минимальными конфигурациями.
По сравнению с Atomikos, Bitronix является проектом с открытым исходным кодом и не имеет коммерческого предложения с поддержкой продукта. Ключевые функции, которые являются частью коммерческого предложения Atomikos, но отсутствуют в Bitronix, включают поддержку микросервисов и возможность декларативного гибкого масштабирования.
9. Заключение
Подводя итог, в этом уроке мы рассмотрели основные детали транзакций. Мы поняли, что такое распределенные транзакции и как такая библиотека, как Atomikos, может облегчить их выполнение. В процессе мы использовали API-интерфейсы Atomikos для создания простого приложения с распределенными транзакциями.
Мы также поняли, как Atomikos работает с другими популярными средами и библиотеками Java. Наконец, мы рассмотрели некоторые доступные нам альтернативы Atomikos.
Как обычно, исходный код этой статьи можно найти на GitHub .