В Spring, если транзакционный метод вызывает другой метод внутри того же класса, откроется ли новая транзакция?

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

Ответ

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

Причина: Вызов метода methodB() внутри класса MyService — это обычный вызов Java-метода, который минует Spring-прокси. Поэтому аннотация @Transactional на methodB() игнорируется, и код выполняется в рамках существующей транзакции methodA().

Пример проблемного кода:

@Service
public class MyService {
    @Transactional
    public void methodA() {
        // Эта транзакция активна
        methodB(); // @Transactional НЕ СРАБОТАЕТ! Вызов в той же транзакции.
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void methodB() {
        // Этот код всё равно выполнится в транзакции methodA
    }
}

Способы заставить новую транзакцию открыться:

  1. Self-injection (внедрение зависимости в самого себя):

    @Service
    public class MyService {
        @Autowired
        private MyService self; // Ссылка на прокси-объект
    
        @Transactional
        public void methodA() {
            self.methodB(); // Вызов через прокси -> откроется новая транзакция
        }
    
        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void methodB() {
            // Логика в новой, независимой транзакции
        }
    }
  2. Вынести метод в отдельный сервис и внедрить его.
  3. Использовать AspectJ вместо Spring AOP (режим mode = AspectJWeaving.ENABLED), но это сложнее и требует дополнительной настройки.

Ключевой вывод: Для работы транзакционных аннотаций вызов должен проходить через Spring-прокси.