middle
Какие уровни propagation существуют?
Propagation определяет, как метод с @Transactional ведёт себя относительно уже существующей транзакции.
| Propagation | Описание |
|---|---|
| REQUIRED (по умолчанию) | Если транзакция есть – присоединиться. Если нет – создать новую |
| REQUIRES_NEW | Всегда создавать новую транзакцию, текущую приостановить |
| SUPPORTS | Если транзакция есть – присоединиться. Если нет – без транзакции |
| NOT_SUPPORTED | Выполнять без транзакции, текущую приостановить |
| MANDATORY | Обязательно должна быть транзакция, иначе – исключение |
| NEVER | Обязательно НЕ должно быть транзакции, иначе – исключение |
| NESTED | Если есть транзакция – создать вложенную (savepoint). Если нет – как REQUIRED |
Пример: REQUIRED vs REQUIRES_NEW
@Service
public class OrderService {
@Transactional // REQUIRED по умолчанию
public void createOrder(Order order) {
orderRepository.save(order);
paymentService.processPayment(order); // присоединится к той же транзакции
auditService.logAction("ORDER_CREATED"); // REQUIRES_NEW -- своя транзакция
}
}
@Service
public class PaymentService {
@Transactional(propagation = Propagation.REQUIRED)
public void processPayment(Order order) {
// работает в той же транзакции, что и createOrder()
// если здесь ошибка -- откатится ВСЯ транзакция, включая order
}
}
@Service
public class AuditService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void logAction(String action) {
// всегда в НОВОЙ транзакции
// даже если основная транзакция откатится, лог сохранится
}
}
NESTED – вложенные транзакции через savepoint
Пример
@Transactional
public void processBatch(List<Item> items) {
for (Item item : items) {
try {
itemService.processItem(item); // NESTED
} catch (Exception e) {
// откатится только обработка этого item (savepoint)
}
}
}
На собеседовании: ключевое – разница между REQUIRED и REQUIRES_NEW. При REQUIRED ошибка внутреннего метода откатит всю внешнюю транзакцию. При REQUIRES_NEW – только внутреннюю. Частая ошибка – путать эти два типа.