← Назад к вопросам

Зачем нужен параметр 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 нужен для управления:

  1. Переиспользованием текущей транзакции (REQUIRED)
  2. Независимостью операций (REQUIRES_NEW - логирование)
  3. Откатом части операции (NESTED)
  4. Запретом транзакции (NEVER)
  5. Условной транзакцией (SUPPORTS)

Праильный выбор propagation критичен для откатов при ошибках.