Транзакция помечена как откатная только по неизвестной причине - PullRequest
0 голосов
/ 22 января 2020

У меня есть некоторый код, подобный приведенному ниже.

public class ServiceImpl implements Service
{
    @Transactional
    public myObject methodOne()
    {
        if (myCondition)
          return methodTwo();
        else 
          anotherMethod();
    }

    public myObject methodTwo()
    {
        int retryCount = 1;
        myObject myObject = null;
        while (retryCount <= 10) {
            try {
                myObject = repository.save();
                break;
            } catch (DataIntegrityViolationException ignored) {
                retryCount++;
            }
        }
        if (myObject == null){
            throw new MyException();
        }
    }
}

Но он выдает исключение

Транзакция молча откатывается, потому что она была помечена как только для отката

даже я поймал methodTwo() и myObject != null. Может кто-нибудь помочь мне, пожалуйста !!!

Ответы [ 2 ]

0 голосов
/ 23 января 2020

Любой RuntimeException внутри транзакции, , о котором Spring узнает , помечает эту транзакцию для отката.

Учитывая, что распространение транзакции для repository.save() равно ТРЕБУЕТСЯ и вызов repository.save() привел к DataIntegrityViolationException, который является подклассом для RuntimeException, транзакция будет помечена для отката, даже если она обрабатывается / перехватывается на methodTwo().

noRollbackFor / noRollbackForClassName атрибуты аннотации @ Transactional могут использоваться для управления поведением отката. Например,

@Transactional(noRollbackFor=DataIntegrityViolationException.class)

Примечание: RuntimeException, о которых Spring узнает , заключается в том, что, если RuntimeException явно генерируется и обрабатывается в том же методе, Spring не будет знать об этом исключение и не помечает окружающую транзакцию для отката. RuntimeException должно распространяться через пружинные прокси, чтобы это произошло, что произошло с вашим вариантом использования.

0 голосов
/ 22 января 2020

Кажется, это из-за правил отката в субтранзакциях.

Как насчет methodTwo вернуть myObject и проверить на methodOne

public class ServiceImpl implements Service
{
    @Transactional
    public myObject methodOne()
    {
        myObject myObject = methodTwo()'
        if (myObject == null){
            throw new MyException();
        }

        return myObject;
    }

    public myObject methodTwo()
    {
        int retryCount = 1;
        myObject myObject = null;
        while (retryCount <= 10) {
            try {
                myObject = repository.save();
                break;
            } catch (DataIntegrityViolationException ignored) {
                retryCount++;
            }
        }
        return myObject;
    }
}
...