Что такое Propagation Type (тип распространения) в транзакциях Spring?

«Что такое Propagation Type (тип распространения) в транзакциях Spring?» — вопрос из категории Spring, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Propagation Type определяет, как должна вести себя транзакция, если она вызывается в контексте уже существующей транзакции. Это поведение задаётся через атрибут propagation аннотации @Transactional.

Основные типы распространения (значения Propagation):

Тип Поведение Когда использовать
REQUIRED (по умолчанию) Использует текущую транзакцию, если она есть. Если нет — создаёт новую. Большинство операций в сервисном слое.
REQUIRES_NEW Всегда создаёт новую транзакцию. Приостанавливает текущую, если она существует. Операции логирования или аудита, которые должны быть сохранены даже при откате основной бизнес-транзакции.
SUPPORTS Работает в текущей транзакции, если она есть. Если нет — выполняется без транзакции. Операции чтения, которые могут работать как в транзакционном, так и в нетранзакционном контексте.
NOT_SUPPORTED Выполняется без транзакции. Приостанавливает текущую транзакцию, если она есть. Вызов методов, несовместимых с транзакциями (например, работа с JMS).
MANDATORY Требует активной транзакции. Если её нет — выбрасывается исключение. Методы, которые должны вызываться только в рамках существующей транзакции.
NEVER Требует отсутствия транзакции. Если она есть — выбрасывается исключение. Проверка, что метод не вызывается в транзакционном контексте.
NESTED Создаёт вложенную транзакцию внутри текущей. Откат вложенной не приводит к откату внешней (если не используется REQUIRED). Сложные операции, где часть шагов может быть откатана независимо. Поддерживается не всеми СУБД (требует savepoints).

Пример:

@Service
public class OrderService {
    @Transactional(propagation = Propagation.REQUIRED)
    public void placeOrder(Order order) {
        // Основная бизнес-логика
        logAudit(order); // Вызов метода с REQUIRES_NEW
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void logAudit(Order order) {
        // Запись в лог-таблицу. Сохранится, даже если placeOrder откатится.
    }
}