Распространение транзакции SpringBoot 2 NESTED не поддерживается

У меня есть проект SpringBoot 2, и я использую jpa данных Spring с гибернацией с MySQL5.7

У меня проблемы со следующим вариантом использования: у меня есть метод службы, который вызывает метод другой службы. Если второй метод службы генерирует исключение во время выполнения, первый метод также помечается как откат, и я больше не могу фиксировать что-либо. Я хотел бы откатить только второй метод и все же что-то зафиксировать в первом.

Я попытался использовать пропаганду.NESTED, но вложенные транзакции не разрешены в спящем режиме (даже если jpaTransactionManager поддерживает их, а MySQL поддерживает точки сохранения).

Как я могу решить эту проблему? Могу ли я каким-то образом настроить вложенность?

Помните, что мне нужен второй метод, чтобы увидеть изменения, зафиксированные первым, поэтому я не могу пометить второй метод как распространение.

Вот пример кода, чтобы прояснить мою проблему:

FirstServiceImpl.java

@Service
public class FirstServiceImpl implements FirstService

@Autowired
SecondService secondService;

@Autowired
FirstServiceRepository firstServiceRepository;

@Transactional
public void firstServiceMethod() {
    //do something
    ...
    FirstEntity firstEntity = firstServiceRepository.findByXXX();
    firstEntity.setStatus(0);
    firstServiceRepository.saveAndFlush(firstEntity);
    ...
    boolean runtimeExceptionHappened = secondService.secondServiceMethod();
    if (runtimeExceptionHappened) {
        firstEntity.setStatus(1);
        firstServiceRepository.save();
    } else {
        firstEntity.setStatus(2);
        firstServiceRepository.save();
    }
}

SecondServiceImpl.java

@Service
public class SecondServiceImpl implements SecondService


@Transactional
public boolean secondServiceMethod() {
    boolean runtimeExceptionHappened = false;
    try {
    //do something that saves to db but that may throw a runtime exception
    ...
    } catch (Exception ex) {
        runtimeExceptionHappened = true;
    }
    return runtimeExceptionHappened;
}

Итак, проблема в том, что когда secondServiceMethod () вызывает исключение времени выполнения, он откатывает свои операции (и это нормально), а затем устанавливает для своей возвращаемой переменной runtimeExceptionHappened значение false, но тогда firstServiceMethod помечается только как откат, а затем

firstEntity.setStatus(1);
firstServiceRepository.save();

не совершено.

Поскольку я не могу использовать NESTED-размножение, как я могу достичь своей цели?

Используйте REQUIRED_NEW

Wilder Valera 08.08.2018 17:16

@WilderValera, как я писал: «... Пожалуйста, помните, мне нужен второй метод, чтобы увидеть изменения, зафиксированные первым, поэтому я не могу пометить второй метод как распространение.REQUIRES_NEW ...». REQUIRES_NEW на secondServiceMethod не увидит изменений firstServiceMethod (я отредактировал образец кода, чтобы подчеркнуть это)

Giorgio Andretti 08.08.2018 17:34

Использование REQUERIED_NEW в secondService должно работать. Я посмотрел на ваш код, и кажется, что вы больше не можете фиксировать из-за saveAndFlush (firstEntity), это может пометить ваш первый tx как совершенный.

Wilder Valera 08.08.2018 21:34

REQUIRES_NEW запускает новую транзакцию, поэтому, если первая фиксация не видна во второй, поскольку первая еще не завершена

Giorgio Andretti 13.08.2018 00:14
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
4
901
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я бы посоветовал вам разбить их на две отдельные транзакции.

В первой транзакции выполните всю работу в firstServiceMethod, которую вы знаете, что хотите зафиксировать. (например, через saveAndFlush). Теперь, когда вы выходите из этого метода, изменения фиксируются, поэтому они будут доступны для последующих вызовов.

Затем пусть то, что называется firstServiceMethod, вызовет новый метод транзакции setFirstEntityStatus(), который вызывает secondServiceMethod и устанавливает соответствующий статус объекта.

По сути, вместо того, чтобы пытаться выполнить NEST транзакции, разделите их на две полностью отдельные транзакции и используйте упорядочение, чтобы гарантировать, что результат 1-й будет доступен для 2-й.

Хорошо, но это звучит как обходной путь и заставляет меня переместить второй вызов службы на контроллере, даже если контроллер может не знать подробных реализаций службы.

Giorgio Andretti 13.08.2018 00:16

Это обходной путь ... обходной путь для того факта, что вложенные транзакции не поддерживаются :-)

Ben M 14.08.2018 18:24

Я надеялся, что есть способ получше, но похоже, что это единственно возможное решение. Я приму ваш ответ, даже если мне не нравится извлекать логику из службы.

Giorgio Andretti 17.08.2018 18:58

Другие вопросы по теме