Ответ
Поведение определяется механизмом AOP (проксирование) и настройкой распространения (propagation) транзакции. По умолчанию (@Transactional(propagation = Propagation.REQUIRED)) внутренний метод не создает новую транзакцию, а присоединяется к существующей.
Проблема (по умолчанию): Поскольку вызов происходит внутри того же класса, он минует Spring AOP прокси. Это означает, что настройки @Transactional внутреннего метода игнорируются, и он выполняется в контексте транзакции внешнего метода.
Пример и решение:
@Service
public class OrderService {
@Transactional
public void placeOrder(Order order) { // Начинает транзакцию Tx1
validate(order);
updateInventory(order); // @Transactional НЕ СРАБОТАЕТ здесь!
// Исключение здесь откатит всю Tx1
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateInventory(Order order) {
// Этот метод выполнится БЕЗ НОВОЙ ТРАНЗАКЦИИ,
// так как вызван напрямую, а не через прокси.
}
}
Как добиться ожидаемого поведения:
- Вынести внутренний метод в отдельный сервис и инжектировать его.
- Использовать самовнедрение (self-injection) через
@Autowired. - Использовать
TransactionTemplateдля программного управления транзакциями.
Вывод: Важно понимать ограничения проксирования Spring, чтобы избежать ошибок в управлении транзакциями.