Ответ
Уровень распространения (Propagation) в @Transactional определяет, как метод должен вести себя по отношению к существующей транзакции.
| Уровень | Описание | Когда использовать |
|---|---|---|
REQUIRED (По умолчанию) |
Использует текущую транзакцию, если она существует. Если нет — создаёт новую. | Стандартный сценарий для большинства операций. |
REQUIRES_NEW |
Всегда создаёт новую транзакцию. Приостанавливает текущую, если она существует. | Для операций, которые должны быть committed независимо от результата внешней транзакции (например, логирование аудита). |
NESTED |
Создаёт вложенную транзакцию внутри текущей. Откат вложенной не приводит к откату внешней (если она не откатится сама). Требует поддержки JDBC 3.0+ и DataSourceTransactionManager. |
Для логически выделенных подопераций, где нужен частичный откат. |
SUPPORTS |
Выполняется в контексте существующей транзакции. Если транзакции нет — работает без неё. | Для операций только чтения, которые могут выполняться как в транзакции, так и без. |
MANDATORY |
Требует активной транзакции. Выбрасывает исключение, если транзакции нет. | Когда метод должен вызываться только в рамках управляемой транзакции. |
NOT_SUPPORTED |
Выполняется без транзакции. Приостанавливает текущую транзакцию, если она есть. | Для операций, несовместимых с транзакциями (например, вызов внешнего API). |
NEVER |
Запрещает выполнение в транзакции. Выбрасывает исключение, если транзакция активна. | Для методов, которые не должны выполняться в транзакционном контексте. |
Практический пример:
@Service
public class BankingService {
@Transactional(propagation = Propagation.REQUIRED)
public void transferMoney(Account from, Account to, BigDecimal amount) {
withdraw(from, amount);
// Даже если deposit() выполнится в новой транзакции,
// откат здесь откатит и withdraw()
deposit(to, amount);
logAudit(from, to, amount); // REQUIRES_NEW — залогируется даже при откате перевода
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void logAudit(Account from, Account to, BigDecimal amount) {
// Логирование в отдельной транзакции
}
}
Важно: REQUIRES_NEW и NESTED создают отдельные физические соединения с БД, что может повлиять на производительность.