← Назад к вопросам
Зачем нужен параметр propagation аннотации @Transactional?
2.0 Middle🔥 111 комментариев
#Spring Framework#Базы данных и SQL
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Зачем нужен параметр propagation аннотации @Transactional?
Определение
propagation — это параметр @Transactional, определяющий как вложенная транзакция взаимодействует с текущей.
@Transactional(propagation = Propagation.REQUIRED)
public void someMethod() { }
Проблема, которую решает propagation
Когда метод A вызывает метод B (оба с @Transactional):
- Запустить новую транзакцию?
- Использовать существующую?
- Запустить независимую?
propagation отвечает на эти вопросы.
1. REQUIRED (по умолчанию)
Использует существующую транзакцию или создаёт новую.
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
methodB(); // Использует транзакцию от A
}
@Transactional(propagation = Propagation.REQUIRED)
public void methodB() {
// ТА ЖЕ транзакция что и в A
}
// Если methodB выбросит exception - ОТКАТИТСЯ ВСЯ транзакция A!
2. REQUIRES_NEW
Всегда создаёт НОВУЮ независимую транзакцию.
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
saveData("A");
methodB(); // Создаёт НОВУЮ транзакцию
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB() {
saveData("B");
// НЕЗАВИСИМАЯ транзакция
}
// Результат: B сохранится даже если A откатится!
3. NESTED
Создаёт точку сохранения (savepoint) в текущей транзакции.
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
saveData("A");
try {
methodB(); // Создаёт SAVEPOINT
} catch (Exception e) {
// Откатить только B, но A сохранится
}
}
@Transactional(propagation = Propagation.NESTED)
public void methodB() {
saveData("B");
throw new RuntimeException("Error!");
}
// Результат:
// - A: СОХРАНЕНА
// - B: ОТКАЧЕНА (до SAVEPOINT)
// - Одна транзакция!
4. NEVER
Метод НЕ должен работать в транзакции. Если есть - ошибка.
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
methodB(); // ERROR!
}
@Transactional(propagation = Propagation.NEVER)
public void methodB() {
// Выбросит IllegalTransactionStateException
}
// Использование: для методов, которые НЕ должны быть в транзакции
5. NOT_SUPPORTED
Работает БЕЗ транзакции. Текущая приостанавливается.
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
saveData("A");
methodB(); // Приостанавливает транзакцию A
saveData("A2");
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void methodB() {
// Работает БЕЗ транзакции
readData();
}
6. SUPPORTS
Использует транзакцию, если есть. Если нет - работает без неё.
@Transactional(propagation = Propagation.SUPPORTS)
public void methodA() {
readData(); // Может быть с транзакцией или без
}
7. MANDATORY
Требует существующую транзакцию. Без неё - ошибка.
@Transactional(propagation = Propagation.MANDATORY)
public void methodA() { }
public void caller() {
methodA(); // ERROR - нет транзакции
}
@Transactional
public void safeCall() {
methodA(); // OK - есть транзакция
}
Практические примеры
REQUIRES_NEW для логирования
@Transactional
public void processOrder(Order order) {
orderRepository.save(order);
logOrderEvent(order); // REQUIRES_NEW
// Если логирование упадёт - ORDER всё равно сохранится
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void logOrderEvent(Order order) {
auditLogRepository.save(new AuditLog(order));
}
NESTED для обработки ошибок
@Transactional
public void transferMoney(Account from, Account to) {
from.withdraw(100);
try {
applyFee(to); // NESTED
} catch (FeeException e) {
// Комиссия откатится, но перевод OK
}
}
Таблица
| Propagation | Переиспользует | Новая | Откатывается |
|---|---|---|---|
| REQUIRED | ДА | если нет | ДА |
| REQUIRES_NEW | НЕТ | всегда | независимо |
| NESTED | ДА (savepoint) | НЕТ | до savepoint |
| NEVER | НЕТ | ошибка | - |
| NOT_SUPPORTED | НЕТ | НЕТ | - |
| SUPPORTS | опционально | НЕТ | если есть |
| MANDATORY | ДА (обязательно) | ошибка | ДА |
Заключение
propagation нужен для управления:
- Переиспользованием текущей транзакции (REQUIRED)
- Независимостью операций (REQUIRES_NEW - логирование)
- Откатом части операции (NESTED)
- Запретом транзакции (NEVER)
- Условной транзакцией (SUPPORTS)
Праильный выбор propagation критичен для откатов при ошибках.