Когда Spring фиксирует (commit) транзакцию при использовании аннотации @Transactional?

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

Ответ

Spring фиксирует (коммитит) транзакцию после успешного выполнения метода, помеченного @Transactional. Если в методе не возникло исключений, приводящих к откату, Spring вызывает commit у менеджера транзакций.

Механизм работы:

  1. Перед вызовом метода Spring открывает транзакцию (или присоединяется к существующей).
  2. Метод выполняется в контексте этой транзакции.
  3. Если метод завершился нормально → Spring коммитит транзакцию.
  4. Если выброшено исключение → Spring проверяет, нужно ли делать rollback.

Правила отката (rollback) по умолчанию:

  • Откат происходит: При RuntimeException и его наследниках (например, NullPointerException, IllegalArgumentException).
  • Откат НЕ происходит: При checked исключениях (например, IOException, SQLException).

Управление поведением:

// Откат при любом Exception (включая checked)
@Transactional(rollbackFor = Exception.class)
public void saveData() throws IOException {
    // ...
}

// НЕ откатывать при определенном RuntimeException
@Transactional(noRollbackFor = IllegalArgumentException.class)
public void updateEntity() {
    // ...
}

Практический пример:

@Service
public class TransferService {
    @Transactional // Транзакция откроется здесь
    public void transfer(Account from, Account to, BigDecimal amount) {
        from.debit(amount);  // Изменения в памяти
        to.credit(amount);   // Изменения в памяти
        // Если здесь выбросится RuntimeException -> ROLLBACK
        // Если исключений нет -> COMMIT после выхода из метода
    }
}

Важно: Фиксация в БД происходит именно в момент коммита, а не после каждого вызова метода внутри транзакции.