В чем разница между методом с @Transactional(распространение = Propagation.SUPPORTS) и методом без @Transactional?

В чем разница между методом с

@Transactional(propagation = Propagation.SUPPORTS)

и метод без @Transactional?

Например:

public class TEst {

    @Transactional
    public void methodWithTransaction1(){
        methodWithSupportsTransaction();
    }

    @Transactional
    public void methodWithTransaction2(){
        methodWithoutTransactional();
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    public void methodWithSupportsTransaction(){

    }

    public void methodWithoutTransactional(){

    }
}

2 ответа

Решение

За исключением небольшой разницы, указанной в javadoc в отношении синхронизации, разница между ними заключается в том, что транзакционный прокси-сервер перехватывает вызов метода, если метод аннотирован с помощью Transactional, и помечает текущую транзакцию, если таковая имеется, как rollbackOnly, если исключение времени выполнения выброшенный из этого метода.

Итак, давайте возьмем пример:

public class A {
    @Autowired B b;

    @Transactional
    public void foo() {
        try {
            b.bar();
        }
        catch (RuntimeException e) {
            // ignore
        }

        ...
    }
}

public class B {
    // @Transactional(propagation = Propagation.SUPPORTS)
    public void bar() {
        throw new RuntimeException();
    }
}

призвание a.foo() начнет транзакцию, если ее еще нет (распространение НЕОБХОДИМО). Затем будет вызвана функция b.bar(), которая выдаст исключение. Исключение поймано a.foo(), который продолжает выполняться, как будто ничего не произошло. В конце a.foo()транзакция будет успешно завершена.

Теперь давайте раскомментируем аннотацию транзакции b.bar(), призвание a.foo() начнет транзакцию, если ее еще нет (распространение НЕОБХОДИМО). Затем будет вызвана функция b.bar(), которая выдаст исключение. Это исключение будет "перехвачено" транзакционным прокси-сервером вокруг B, который помечает транзакцию как rollbackOnly. Тогда исключение будет распространяться на А. a.foo(), Исключение поймано a.foo(), который продолжает выполняться, как будто ничего не произошло. В конце a.foo()транзакция будет зафиксирована, но эта фиксация не будет выполнена, поскольку транзакция уже помечена как rollbackOnly. Вызывающая функция a.foo() получит исключение TransactionSystemException.

Spring поддерживает два типа управления транзакциями: программный и декларативный.

Программное управление транзакциями. Таким образом, транзакции должны обрабатываться нами. Например-

EntityTransaction tran = entityManager.getTransaction(); 
try { 
    tran.begin(); 
    methodWithoutTransactional();
    tran.commit(); 
} catch(Exception ex) { 
    tran.rollback(); 
    throw ex; 
}

Декларативное управление транзакциями. Таким образом, мы можем отделить код управления транзакциями от нашей бизнес-логики, просто используя аннотации или конфигурацию на основе XML. Что вы уже сделали в примере кода

@Transactional
public void methodWithTransaction1(){
    methodWithSupportsTransaction();
}

Для аннотации @Transactional, если мы не определим тип распространения, по умолчанию будет применяться PROPAGATION_REQUIRED. Вы можете найти документацию здесь.

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