← Назад к вопросам

Что такое @Transactional в Spring и как работает транзакционность?

2.0 Middle🔥 251 комментариев
#Spring Framework

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

@Transactional в Spring: полное руководство

@Transactional — это аннотация Spring, которая управляет транзакциями на уровне методов и классов. Это один из основных инструментов для обеспечения консистентности данных в приложении.

Основные концепции

Транзакция — это набор операций, которые выполняются либо полностью, либо откатываются целиком (ACID принципы). @Transactional автоматически открывает транзакцию перед методом и коммитит её после успешного завершения.

Базовое использование

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;
    
    @Transactional
    public User createUser(String name) {
        User user = new User(name);
        return userRepository.save(user);
    }
    
    @Transactional(readOnly = true)
    public User findUserById(Long id) {
        return userRepository.findById(id).orElse(null);
    }
}

Как это работает под капотом

Spring использует AOP (Aspect-Oriented Programming) для создания прокси вокруг объектов. Перед методом открывается транзакция, после — коммитится или откатывается в зависимости от результата.

Уровни изоляции

  • READ_UNCOMMITTED — грязное чтение, нарушает консистентность
  • READ_COMMITTED — стандарт, не читаем незаяленные данные
  • REPEATABLE_READ — фантомное чтение невозможно
  • SERIALIZABLE — полная изоляция, может быть медленно

Распространение (propagation)

@Transactional(propagation = Propagation.REQUIRED)
// Использует существующую или создаёт новую (default)

@Transactional(propagation = Propagation.REQUIRES_NEW)
// Всегда создаёт новую

@Transactional(propagation = Propagation.NESTED)
// Создаёт savepoint

Обработка исключений

@Transactional(rollbackFor = Exception.class)
// Откатывается при ЛЮБОМ исключении

@Transactional(noRollbackFor = ValidationException.class)
// Не откатывается при ValidationException

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

@Transactional
public void transferMoney(Long fromId, Long toId, BigDecimal amount) {
    Account from = accountRepository.findById(fromId).orElseThrow();
    Account to = accountRepository.findById(toId).orElseThrow();
    
    if (from.getBalance().compareTo(amount) < 0) {
        throw new InsufficientFundsException();
    }
    
    from.withdraw(amount);
    to.deposit(amount);
}

Если исключение — откатываются обе операции.

Частые ошибки

  1. Вызов @Transactional из того же класса без прокси
  2. Незаявленные RuntimeException, которые не откатят транзакцию
  3. Дорогие операции внутри @Transactional
  4. Забыли указать rollbackFor для checked exceptions

Оптимизация

  • Используй readOnly = true для методов без изменений
  • Минимизируй время в транзакции
  • Рассмотри Propagation.REQUIRES_NEW для независимых операций
  • Избегай N+1 queries внутри транзакции

@Transactional — мощный инструмент, но требует понимания ACID принципов и особенностей реализации.