Как в вашем примере, если бы inner()
имел:
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void inner(){
//some logic
}
Тогда, если бы он вызвал исключение из второго вызова в цикле outer()
, изменения от первого вызова имели быуже зафиксировано - его REQUIRES_NEW
.
Если бы inner()
имел:
@Transactional(propagation=Propagation.NESTED)
public void inner(){
//some logic
}
Тогда изменения от первого вызова будут откатываться - потому что в перехватчике нет блокаouter()
.
Точка, в которой уровень распространения на inner()
действительно начинает иметь значение, заключается в том, будет ли цикл outer()
обрабатывать исключения в inner()
:
@Transactional
public void outer() {
for (int i = 0; i < 100500; i++) {
try {
inner();
} catch (Exception ex) {
// Report and continue
}
}
// Something else that could fail
}
Очевидно, что REQUIRES_NEW
и NESTED
сохранят изменения только от успешных вызовов inner()
.Ключевое отличие заключается в том, что с NESTED
есть возможность выбросить все это, если в outer()
последует сбой.
Как вы говорите, другой фактор - это масштабируемость - некоторые базы данныхвозможно, не оценят размер родительской транзакции с NESTED
распространением.
Также, возможно, стоит сказать - хотя я подозреваю, что в этом примере мы стремились к ясности.Прямой вызов this.inner()
обходится консультантом транзакций Spring.Необходимо разрешить вводить «рекомендованный компонент», чтобы аннотация @Transactional
могла выполнять свою магию до и после вызова - например, nextAutowiredBean.inner()
.