Gymterview
senior

Какие подводные камни есть у @Transactional?

Это один из самых популярных вопросов на собеседованиях. Подводные камни @Transactional – проверка глубины понимания Spring.

1. Self-invocation (вызов из того же класса)

@Transactional работает через прокси. Вызов метода внутри того же класса обходит прокси:

Пример
@Service
public class UserService {
    @Transactional
    public void updateUser(User user) {
        userRepository.save(user);
    }

    public void processUser(Long userId) {
        User user = userRepository.findById(userId).orElseThrow();
        this.updateUser(user); // @Transactional НЕ сработает!
    }
}

Решения: вынести в другой сервис или использовать self-injection (@Autowired private UserService self;).

2. Checked exceptions не вызывают откат

Пример
@Transactional // НЕ откатится при IOException!
public void saveFile(MultipartFile file) throws IOException {
    userRepository.save(user);
    fileStorage.store(file); // бросает IOException -- транзакция коммитится!
}

// Правильно:
@Transactional(rollbackFor = Exception.class)
public void saveFile(MultipartFile file) throws IOException { }

3. @Transactional на private методе не работает

Spring AOP не может создать прокси для private-метода.

4. Проглатывание исключения

Пример
@Transactional
public void process() {
    try {
        riskyOperation();
    } catch (Exception e) {
        log.error("Error", e);
        // исключение проглочено -- транзакция закоммитится,
        // хотя данные могут быть в некорректном состоянии
    }
}

5. Долгие операции внутри транзакции

Пример
@Transactional
public void processOrder(Order order) {
    orderRepository.save(order);
    emailService.sendEmail(order); // долгая операция -- блокирует соединение с БД!
}

Отправку уведомлений нужно выносить за пределы транзакции или делать асинхронно.

6. Не указан TransactionManager при нескольких DataSource

Пример
@Transactional("secondaryTransactionManager")
public void saveToSecondaryDb(Data data) { }

На собеседовании: это вопрос для senior-уровня. Интервьюер ждёт минимум 3-4 подводных камня с примерами. Главные: self-invocation, checked exceptions, private-методы. Частая ошибка – не знать про self-invocation или думать, что любое исключение откатит транзакцию.