В каких случаях аннотация @Transactional в Spring не выполнит откат транзакции?

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

Ответ

@Transactional не выполнит откат транзакции в следующих случаях:

  1. Выброшено checked-исключение, не указанное в rollbackFor. По умолчанию откат происходит только для RuntimeException и Error.

    @Transactional
    public void saveData() throws IOException {
        // ...
        throw new IOException(); // Отката НЕ будет
    }
  2. Исключение перехвачено и не проброшено за пределы метода.

    @Transactional
    public void process() {
        try {
            riskyOperation(); // Может бросить RuntimeException
        } catch (RuntimeException e) {
            // Исключение поглощено -> отката НЕ будет
            log.error("Ошибка проигнорирована", e);
        }
    }
  3. Метод вызван изнутри того же класса (self-invocation). Прокси Spring AOP не перехватывает внутренние вызовы.

    @Service
    public class MyService {
        public void outer() {
            this.inner(); // Вызов через `this` -> @Transactional на inner() не сработает
        }
        @Transactional
        public void inner() { /* ... */ }
    }
  4. Используется распространение Propagation.NOT_SUPPORTED или Propagation.NEVER. Эти атрибуты приостанавливают или запрещают выполнение в транзакции.

  5. Транзакция помечена как readOnly = true. Для операций модификации это может привести к исключению, а не к откату.