Что такое транзакционный метод в Spring и каковы его свойства?

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

Ответ

Транзакционный метод в Spring — это метод, помеченный аннотацией @Transactional. Spring создаёт для него прокси, который управляет транзакцией: начинает её перед вызовом метода и фиксирует (commit) или откатывает (rollback) после.

Свойства транзакции (ACID), обеспечиваемые аннотацией:

  • Atomicity (Атомарность): Все операции метода выполняются как единое целое.
  • Consistency (Согласованность): Транзакция переводит базу данных из одного согласованного состояния в другое.
  • Isolation (Изоляция): Параллельные транзакции не мешают друг другу (уровень настраивается).
  • Durability (Долговечность): Результаты зафиксированной транзакции сохраняются после сбоя системы.

Пример и ключевые параметры аннотации:

@Service
public class BankService {
    @Transactional(
        isolation = Isolation.READ_COMMITTED,
        propagation = Propagation.REQUIRED,
        rollbackFor = {InsufficientFundsException.class},
        timeout = 30
    )
    public void transferMoney(Long fromId, Long toId, BigDecimal amount) {
        Account from = accountRepository.findById(fromId).orElseThrow();
        Account to = accountRepository.findById(toId).orElseThrow();
        from.debit(amount); // UPDATE в БД
        to.credit(amount);  // Ещё один UPDATE
        // Если здесь выбросится исключение InsufficientFundsException,
        // оба UPDATE будут откачены (rollback).
    }
}

Важные правила работы @Transactional:

  1. Public методы: Аннотация работает только для public-методов, вызываемых извне класса (через Spring Proxy).
  2. Откат по умолчанию: Происходит при unchecked исключениях (RuntimeException и его наследники). Для checked исключений нужно указывать параметр rollbackFor.
  3. Распространение (Propagation): Определяет поведение метода, если он вызывается в контексте существующей транзакции (например, REQUIRED — использует текущую, REQUIRES_NEW — начинает новую).