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

Что такое Propagation?

2.0 Middle🔥 251 комментариев
#Spring Framework

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое Propagation в Spring

Propagation (распространение) в Spring определяет, как транзакция ведет себя при вызове другого метода с @Transactional внутри уже выполняющейся транзакции. Это управление жизненным циклом транзакций.

Основные типы Propagation

1. REQUIRED (по умолчанию)

Это наиболее часто используемое значение. Использует текущую транзакцию, если она есть. Если нет — создает новую.

@Service
public class OrderService {
    @Autowired
    private PaymentService paymentService;
    
    @Transactional(propagation = Propagation.REQUIRED)
    public void processOrder(Order order) {
        // Если есть активная транзакция, используем её
        // Если нет — создаем новую
        saveOrder(order);
        paymentService.processPayment(order);
        // Если processPayment выбросит исключение,
        // вся транзакция откатится
    }
    
    @Transactional(propagation = Propagation.REQUIRED)
    public void processPayment(Order order) {
        // Использует ту же транзакцию что и processOrder
        paymentRepository.save(payment);
    }
}

2. REQUIRES_NEW

Засчитает новую транзакцию, приостанавливая текущую (если она есть).

@Service
public class OrderService {
    @Autowired
    private LoggingService loggingService;
    
    @Transactional(propagation = Propagation.REQUIRED)
    public void createOrder(Order order) {
        orderRepository.save(order);
        loggingService.logOrderCreation(order); // новая транзакция
    }
}

@Service
public class LoggingService {
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void logOrderCreation(Order order) {
        // Эта транзакция будет независимой
        // Даже если основной заказ откатится, лог сохранится
        logRepository.save(new Log("Order created"));
    }
}

Практический пример: логирование должно быть отдельной транзакцией, чтобы ошибка в основной операции не удаляла логи.

3. SUPPORTED

Использует текущую транзакцию, если она есть. Если нет — выполняется без транзакции.

@Service
public class ReportService {
    @Transactional(propagation = Propagation.SUPPORTED, readOnly = true)
    public Report generateReport() {
        // Если есть транзакция, используем её
        // Если нет — просто читаем данные
        return reportRepository.findAll();
    }
}

4. NOT_SUPPORTED

Выполняется БЕЗ транзакции. Если есть текущая транзакция, она приостанавливается.

@Service
public class ExternalService {
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void callExternalAPI() {
        // Выполняется без транзакции
        // Полезно для вызовов, которые не должны быть в транзакции
        externalApi.call();
    }
}

5. MANDATORY

Требует наличие активной транзакции. Если её нет — выбросит исключение.

@Service
public class PaymentService {
    @Transactional(propagation = Propagation.MANDATORY)
    public void processPayment(Payment payment) {
        // Этот метод ДОЛЖЕН быть вызван в контексте транзакции
        // Иначе будет thrown IllegalTransactionStateException
        paymentRepository.save(payment);
    }
}

// Вызов без транзакции приведет к ошибке
paymentService.processPayment(payment); // ERROR!

// Правильный вызов внутри другого @Transactional метода
@Transactional
public void orderWithPayment(Order order) {
    processPayment(order.getPayment()); // OK
}

6. NEVER

Никогда не должна быть активной транзакция. Если она есть — выбросит исключение.

@Service
public class AuditService {
    @Transactional(propagation = Propagation.NEVER)
    public void auditAction(String action) {
        // Этот метод НЕ должен быть в транзакции
        auditRepository.save(action);
    }
}

7. NESTED

Создает вложенную транзакцию (savepoint). Если вложенная откатится, основная может продолжить.

@Service
public class OrderService {
    @Transactional
    public void complexOrder(Order order) {
        saveOrder(order);
        try {
            processDiscount(order); // вложенная транзакция
        } catch (DiscountException e) {
            // Откат только скидки, заказ остается
            log.warn("Discount failed, order saved without discount");
        }
    }
    
    @Transactional(propagation = Propagation.NESTED)
    public void processDiscount(Order order) {
        // Вложенная транзакция с savepoint
        discountRepository.apply(order);
    }
}

Сравнительная таблица

PropagationТекущая ТХСоздает новуюЕсли ошибка
REQUIREDИспользуетЕсли нетОткат всей ТХ
REQUIRES_NEWПриостанавливаетДаОткат только новой ТХ
SUPPORTEDИспользуетНетБез ТХ
NOT_SUPPORTEDПриостанавливаетНетБез ТХ
MANDATORYТребуетНетОшибка если нет ТХ
NEVERОшибкаНетОшибка если есть ТХ
NESTEDВложеннаяSavepointОткат только вложенной

Практические примеры использования

// 1. Логирование независимо от основной операции
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void log(String message) {
    logRepository.save(new Log(message));
}

// 2. Операции, которые могут быть без транзакции
@Transactional(propagation = Propagation.SUPPORTED, readOnly = true)
public List<Report> getReports() {
    return reportRepository.findAll();
}

// 3. Обязательное наличие транзакции
@Transactional(propagation = Propagation.MANDATORY)
public void criticalOperation() {
    // Должна быть транзакция
}