Ответ
Propagation (распространение транзакций) — это атрибут транзакции в Spring, определяющий, как должна вести себя транзакция, когда метод, помеченный @Transactional, вызывается из другого транзакционного метода.
Типы распространения (Propagation):
| Тип | Поведение | Когда использовать |
|---|---|---|
REQUIRED (по умолчанию) |
Использует существующую транзакцию. Если её нет — создаёт новую. | Стандартный сценарий, когда операции должны выполняться в одной транзакции. |
REQUIRES_NEW |
Всегда создаёт новую, независимую транзакцию. Приостанавливает текущую, если она существует. | Критичные операции (логирование, аудит), которые должны быть сохранены даже при откате основной транзакции. |
SUPPORTS |
Выполняется в существующей транзакции, если она есть. Если нет — выполняется без транзакции. | Методы, которые могут работать как в транзакционном, так и в нетранзакционном контексте (например, read-only операции). |
NOT_SUPPORTED |
Выполняется без транзакции. Приостанавливает текущую транзакцию, если она существует. | Операции, несовместимые с транзакциями (например, вызов внешнего API). |
MANDATORY |
Требует активной транзакции. Если её нет — выбрасывает IllegalTransactionStateException. |
Методы, которые должны вызываться только в рамках уже начатой бизнес-транзакции. |
NEVER |
Требует отсутствия транзакции. Если она есть — выбрасывает IllegalTransactionStateException. |
Методы, которые не должны выполняться в транзакционном контексте (проверка изоляции). |
NESTED |
Создаёт вложенную транзакцию внутри существующей, если она есть. Если нет — ведёт себя как REQUIRED. Откат вложенной транзакции не приводит к откату внешней. |
Сложные сценарии, где часть работы можно безопасно откатить независимо (работает только с некоторыми JDBC-драйверами, например, для СУБД, поддерживающих savepoints). |
Примеры:
@Service
public class OrderService {
@Transactional(propagation = Propagation.REQUIRED)
public void placeOrder(Order order) {
// Основная логика заказа в транзакции
orderRepository.save(order);
inventoryService.updateStock(order); // Вызов метода с REQUIRES_NEW
// Если updateStock выбросит исключение, order НЕ будет откачен,
// но stock обновится (т.к. его транзакция завершилась).
}
}
@Service
public class InventoryService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateStock(Order order) {
// Эта операция выполняется в своей собственной транзакции.
// Её коммит или откат не влияет на транзакцию placeOrder.
inventoryRepository.decrementStock(order.getItemId(), order.getQuantity());
}
}
Важно: Поведение NESTED зависит от поддержки JDBC-драйвером точек сохранения (savepoints).