Как использовать аннотацию @Transactional в Spring?

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

Ответ

Аннотация @Transactional декларативно управляет границами транзакций в Spring. Она применяется на уровне метода или класса.

Базовый пример:

@Service
public class TransferService {
    @Autowired
    private AccountRepository accountRepository;

    @Transactional // Весь метод выполняется в одной транзакции
    public void transferMoney(Long fromId, Long toId, BigDecimal amount) {
        Account fromAccount = accountRepository.findById(fromId).orElseThrow();
        Account toAccount = accountRepository.findById(toId).orElseThrow();

        if (fromAccount.getBalance().compareTo(amount) < 0) {
            throw new InsufficientFundsException(); // RuntimeException вызовет rollback
        }

        fromAccount.debit(amount);
        toAccount.credit(amount);
        // Сохранение не требуется явно, если используется контекст persistence с flush-mode AUTO (по умолчанию в @Transactional)
    }
}

Ключевые атрибуты для настройки:

  • propagation: Определяет поведение транзакции относительно существующего контекста (например, REQUIRED, REQUIRES_NEW).
  • isolation: Уровень изоляции (например, READ_COMMITTED, SERIALIZABLE).
  • rollbackFor / noRollbackFor: Какие исключения вызывают или не вызывают откат.
  • readOnly: Флаг только для чтения (оптимизация для true).
  • timeout: Таймаут транзакции в секундах.

Важно: @Transactional работает через AOP-прокси, поэтому вызовы методов внутри одного класса не будут перехвачены прокси. По умолчанию откат происходит только при непроверяемых исключениях (RuntimeException и его наследниках).