Ответ
Аннотация @Transactional в Spring не работает для private (и protected) методов из-за ограничений механизма проксирования, лежащего в основе декларативного управления транзакциями.
Причина: Spring AOP (и стандартный механизм прокси на основе JDK или CGLIB) не может перехватить вызов приватного метода.
- Прокси-объект оборачивает целевой бин и перехватывает вызовы его методов, чтобы добавить transactional-логику (открытие/закрытие транзакции).
- Вызов
private-метода происходит внутри самого класса, минуя прокси. Это называется self-invocation.
Пример проблемы:
@Service
public class UserService {
public void processUser() {
updateUser(); // Внутренний вызов -> прокси не участвует!
}
@Transactional // НЕ СРАБОТАЕТ!
private void updateUser() {
// Логика обновления в БД
}
}
Решения:
- Сделать метод
public(илиprotectedдля CGLIB-прокси). Это стандартное решение. -
Использовать
TransactionTemplateдля программного управления транзакциями внутри метода.@Service public class UserService { @Autowired private TransactionTemplate transactionTemplate; private void updateUser() { transactionTemplate.execute(status -> { // Логика в транзакции return null; }); } } - Внедрить зависимость от самого себя (через
AopContextили@Autowired), чтобы вызвать метод через прокси. Этот подход считается антипаттерном и нарушает инкапсуляцию.
Вывод: Для работы @Transactional метод должен быть виден для прокси, то есть иметь как минимум protected видимость (при использовании CGLIB) или public.