Почему в Spring транзакция (@Transactional) не работает для private методов?

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

Ответ

Транзакционность в Spring реализуется через AOP-прокси. Прокси-объект оборачивает целевой бин, чтобы перехватывать вызовы публичных методов и добавлять к ним управление транзакциями.

Причина:

  • privatefinal) методы не могут быть переопределены в подклассе, который создается механизмом проксирования (CGLIB).
  • Прокси не может перехватить вызов private-метода, так как он вызывается только внутри самого класса, минуя прокси-обертку.

Пример проблемы:

@Service
public class TransferService {
    @Transactional
    private void updateBalance(Account acc, BigDecimal amount) { // НЕ СРАБОТАЕТ
        // Логика обновления баланса
    }

    public void transfer(Account from, Account to) {
        updateBalance(from, BigDecimal.valueOf(-100)); // Вызов внутри класса, прокси игнорируется
        updateBalance(to, BigDecimal.valueOf(100));
    }
}

Решение: Сделать метод public или protected (если используется CGLIB). Лучшая практика — применять @Transactional только к публичным методам сервисного слоя.