Управление транзакциями
Jmix поддерживает оба стандартных способа управления транзакциями в приложениях Spring: декларативный (с аннотациями) и программный.
Декларативное управление транзакциями
Самый простой способ управления транзакциями в приложениях Jmix – это использовать аннотацию @org.springframework.transaction.annotation.Transactional. Она указывает метод, который должен выполняться внутри транзакции базы данных. При использовании на уровне класса @Transactional применяется ко всем методам этого класса и его подклассов.
Аннотация @Transactional автоматически создаст транзакцию при вызове метода, а коммит или откат будут управляться Spring неявно. Таким образом, декларативное управление транзакциями позволяет сократить объем шаблонного кода.
Для уточнения поведения @Transactional можно использовать ряд параметров, например, уровень изоляции или распространения: эти параметры описаны в документации Spring.
Пример использования @Transactional для обновления нескольких сущностей в рамках одной транзакции:
@Transactional (1)
public void makeDiscountsForAll() {
    List<Order> orders = dataManager.load(Order.class)
            .query("select o from sample_Order o where o.customer is not null")
            .list();
    for (Order order : orders) {
        BigDecimal newTotal = orderService.calculateDiscount(order);
        order.setAmount(newTotal);
        dataManager.save(order);
        Customer customer = customerService.updateCustomerGrade(order.getCustomer());
        dataManager.save(customer);
    }
}| 1 | Просто разместите аннотацию, Spring сделает все остальное: прокси будет создан для инжектирования транзакционной логики до (запуска транзакции) и после (коммита или отката) запущенного метода. | 
| Имейте в виду, что декларативная разметка работает только в том случае, если метод вызывается в экземпляре, инжектированном в другой бин, или полученном с помощью ApplicationContext.getBean(), то есть через созданный контейнером прокси. Вызов аннотированного метода из другого метода того же объекта не приведет к запуску транзакции. | 
Если нужно объявить транзакцию для дополнительного хранилища данных, укажите имя бина менеджера транзакций хранилища в аннотации @Transactional. Если хранилище данных создано с помощью Studio, имя бина его менеджера транзакций – <DATA-STORE-NAME>TransactionManager. Например, если имя хранилища данных – db1, транзакционный метод для него определяется следующим образом:
@Transactional("db1TransactionManager")
public void makeChangesInDb1DataStore() {
    // ...
}Программное управление транзакциями
Для программного управления транзакциями Spring предлагает org.springframework.transaction.support.TransactionTemplate.
Создание TransactionTemplate
Чтобы создать экземпляр TransactionTemplate, можно объявить бин в основном классе приложения (с аннотацией @SpringBootApplication) и инициализировать его с помощью PlatformTransactionManager:
@Bean
@Primary
TransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager) {
    return new TransactionTemplate(transactionManager);
}Теперь вы можете инжектировать TransactionTemplate в любой бин приложения:
@Autowired
private TransactionTemplate transactionTemplate;Для дополнительных хранилищ данных, если таковые имеются, требуются собственные экземпляры TransactionTemplate. Если создать дополнительное хранилище данных с помощью Studio, класс конфигурации Spring хранилища данных будет автоматически создан с некоторыми бинами. Добавьте новый бин для создания TransactionTemplate с аннотацией Qualifier следующим образом:
@Bean
TransactionTemplate db1TransactionTemplate(
        @Qualifier("db1TransactionManager") (1)
        PlatformTransactionManager transactionManager) {
    return new TransactionTemplate(transactionManager);
}| 1 | Аннотация @Qualifierиспользуется для инжектирования конкретного бина по его имени: в данном случае этоPlatformTransactionManager, определенный для дополнительного хранилища данных с именемdb1. | 
Таким образом, можно инжектировать необходимый TransactionTemplate с аннотацией Qualifier для управления транзакциями в дополнительном хранилище данных:
@Autowired
@Qualifier("db1TransactionTemplate") (1)
private TransactionTemplate db1TransactionTemplate;| 1 | Здесь аннотация @Qualifierпозволяет Spring выбрать бин, который мы определили выше для хранилища данныхdb1. | 
Если вам не нужно, чтобы TransactionTemplate был доступен везде в проекте, можно создать его локально в бине, используя PlatformTransactionManager. В приведенном ниже примере показано создание двух шаблонов с различным поведением при распространении:
@Autowired
private PlatformTransactionManager transactionManager;
// joins existing transaction
public TransactionTemplate getTransactionTemplate() {
    return new TransactionTemplate(transactionManager);
}
// always creates new transaction
public TransactionTemplate getRequiresNewTransactionTemplate() {
    TransactionTemplate tt = new TransactionTemplate(transactionManager);
    tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
    return tt;
}Использование TransactionTemplate
Используйте метод execute() для запуска блока кода внутри транзакции. Этот метод обрабатывает жизненный цикл транзакции и возможные исключения, поэтому вам не нужно обрабатывать их явно:
public UUID createOrderAndReturnId() {
    return transactionTemplate.execute(status -> {
        Customer customer = dataManager.create(Customer.class);
        customer.setName("Alice");
        customer = dataManager.save(customer);
        Order order = dataManager.create(Order.class);
        order.setCustomer(customer);
        order = dataManager.save(order);
        return order.getId();
    });
}Если вам не нужно возвращать какой-либо результат из блока транзакционного кода, можно использовать метод executeWithoutResult(), который является производным от execute(), но использует интерфейс обратного вызова TransactionCallbackWithoutResult:
public void createOrder() {
    transactionTemplate.executeWithoutResult(status -> {
        Customer customer = dataManager.create(Customer.class);
        customer.setName("Alice");
        customer = dataManager.save(customer);
        Order order = dataManager.create(Order.class);
        order.setCustomer(customer);
        dataManager.save(order);
    });
} Параметры транзакции по умолчанию, такие как режим распространения, уровень изоляции, время ожидания и т.д., Можно настроить с помощью сеттеров TransactionTemplate.