Что означает поведение распространения REQUIRED в Spring?

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

Ответ

REQUIRED — это наиболее часто используемое поведение распространения (Propagation) транзакций в Spring Framework. Оно указывает, что метод должен выполняться в рамках транзакции: если транзакция уже существует, она будет использована; если нет — будет создана новая.

Логика работы:

  1. Транзакция существует: Метод присоединяется к текущей транзакции.
  2. Транзакции нет: Spring создаёт новую физическую транзакцию перед выполнением метода и фиксирует/откатывает её после.

Пример сценариев:

@Service
public class OrderService {
    @Transactional(propagation = Propagation.REQUIRED)
    public void placeOrder(Order order) {
        // 1. Если вызван извне без транзакции -> создаётся НОВАЯ транзакция.
        // 2. Если вызван из другого @Transactional метода -> используется СУЩЕСТВУЮЩАЯ.
        orderRepository.save(order);
        inventoryService.updateStock(order); // Вызов метода с REQUIRED
    }
}

@Service
public class InventoryService {
    @Transactional(propagation = Propagation.REQUIRED)
    public void updateStock(Order order) {
        // При вызове из placeOrder() используется ТА ЖЕ транзакция.
        // Откат в этом методе приведёт к откату всей внешней транзакции.
        inventoryRepository.decrement(order.getItemId(), order.getQuantity());
    }
}

Поведение при ошибках:

  • Если метод с REQUIRED является инициатором транзакции, он определяет её границы — откат происходит при любом неперехваченном RuntimeException.
  • Если метод присоединяется к существующей транзакции, он становится её частью. Любой откат внутри этого метода (или в другом месте цепочки) приведёт к откату всей внешней транзакции.

Аналогия: REQUIRED работает как "присоединись или создай новую".

Объявление:

// Аннотацией
@Transactional(propagation = Propagation.REQUIRED) // propagation можно опустить, т.к. REQUIRED — значение по умолчанию.
public void businessMethod() { ... }

// Декларативно (XML)
<tx:advice id="txAdvice">
    <tx:attributes>
        <tx:method name="*" propagation="REQUIRED"/>
    </tx:attributes>
</tx:advice>

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