Ответ
Без @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 обязателен.