Приведите пример бизнес-логики метода, когда обязательно нужно использовать @Transactional в Spring
Что проверяют
Понимаете ли вы, что транзакция нужна не «на всякий случай», а там, где несколько изменений в базе обязаны примениться целиком или не примениться вовсе. Заодно смотрят, знаете ли вы, что @Transactional работает через прокси, а не магией, и где эта прокси перестаёт действовать.
Как отвечать
Берите пример, где в одном методе идут два и больше изменяющих запроса, связанных общим инвариантом. Классика: перевод средств между счетами, где списание и зачисление обязаны быть одной операцией. Не хуже и оформление заказа: создали заказ, уменьшили остаток на складе, записали позиции. Если остаток уменьшился, а заказ не сохранился, товар исчезнет из продажи ни за что.
@Transactional
public void placeOrder(Long userId, List<Item> items) {
Order order = orderRepository.save(new Order(userId));
for (Item item : items) {
stockService.reserve(item.getSku(), item.getQty());
orderItemRepository.save(new OrderItem(order, item));
}
}Дальше назовите второй мотив, про который забывают: транзакция задаёт границу персистентного контекста. Внутри неё работает отслеживание изменений, то есть изменённая сущность сохранится без явного вызова save, и подтягиваются ленивые связи. Для чтения полезен @Transactional(readOnly = true): лишние снимки сущностей не создаются, а запрос можно отправить на реплику.
Где спотыкаются
Ставят аннотацию на метод, который вызывается изнутри того же класса. Прокси в такой ситуации минуется, транзакции нет, а код выглядит совершенно корректным. То же с приватными и финальными методами: проксировать нечего.
Второе: ждут отката на проверяемом исключении. По умолчанию Spring откатывает только на наследниках RuntimeException и Error, а исключение, перехваченное внутри самого метода, не откатывает вообще ничего.
Третье: заворачивают в транзакцию поход во внешнюю систему, письмо или запрос по HTTP. База держит блокировки всё время сетевого вызова, а откатить отправленное письмо нельзя. Такие действия выносят за коммит.