Что происходит при отсутствии @Transactional над методом сохранения в Spring?

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

Ответ

Без @Transactional метод выполняется без управляемой транзакции, что приводит к:

  • Отсутствие атомарности – каждая операция с БД выполняется в отдельной транзакции
  • Нет автоматического отката при исключениях
  • Проблемы с контекстом persistence (например, LazyInitializationException)

Пример проблемы:

// БЕЗ @Transactional
public void createUser(User user) {
    userRepository.save(user);          // Транзакция 1: COMMIT
    auditRepository.logCreation(user);  // Транзакция 2: если FAIL, user уже сохранён
    sendNotification(user);             // Если исключение здесь, данные не откатятся
}

Сравнение поведения:

Аспект Без @Transactional С @Transactional
Атомарность Нет Да (все операции в одной транзакции)
Откат при исключении Нет Да (по умолчанию для RuntimeException)
Изоляция По умолчанию БД Настраиваемая (@Transactional(isolation = ...))
Propagation Нет поддержки Есть (REQUIRED, REQUIRES_NEW и др.)

Правильная реализация:

@Service
public class UserService {

    @Transactional  // Все вызовы репозиториев в одной транзакции
    public User createUser(UserDto dto) {
        User user = new User(dto.getName(), dto.getEmail());
        user = userRepository.save(user);  // INSERT

        auditRepository.log("USER_CREATED", user.getId());  // INSERT в той же транзакции

        if (dto.getEmail() == null) {
            throw new IllegalArgumentException("Email required");  // ОБА INSERT откатятся!
        }

        return user;
    }
}

Важно: В Spring Data JPA методы репозитория по умолчанию имеют транзакционность, но для сервисных методов, объединяющих несколько операций, @Transactional обязателен.