@Transactional и private-метод внутри публичного — транзакция срабатывает не там, где ждёте
Это не про self-invocation через this — этот случай разбирали отдельно. Ловушка тоньше: публичный метод с @Transactional вызывает несколько приватных методов того же класса, и один из них кидает исключение на середине работы.
Proxy Spring оборачивает только публичный метод, на который повешена аннотация. Всё, что происходит внутри — вызовы приватных методов — идёт как обычный вызов Java, без прохождения через advice. Это нормально: транзакция всё равно открыта на входе в публичный метод и закроется на выходе или при исключении.
Проблема в другом: если один из приватных методов сам ловит исключение и логирует его, а наружу отдаёт null или флаг ошибки — транзакция не узнает, что что-то пошло не так. Она увидит нормальный возврат из публичного метода и закоммитит всё, что успело записаться раньше.
@Transactional public void processOrder(Order order) { saveOrder(order); boolean ok = chargePayment(order); if (!ok) { log.warn("payment failed"); } }
private boolean chargePayment(Order order) { try { paymentClient.charge(order); return true; } catch (Exception e) { log.error("charge error", e); return false; } }
Заказ сохранён, платёж не прошёл, но транзакция коммитит обе операции — потому что исключение проглочено на два уровня выше того места, где реально нужен откат.
Следом спросят: как правильно вернуть контроль транзакции при такой структуре. Правильный ответ — либо перебрасывать исключение из приватного метода наружу, либо явно вызывать TransactionAspectSupport.currentTransactionStatus().setRollbackOnly() в месте, где решили не пробрасывать exception. Второй вариант используют, когда бизнес-логика хочет залогировать детали до отката.
@Transactional откатывает по исключению, а не по факту ошибки в бизнес-логике — если код решил ошибку проглотить, транзакция об этом никогда не узнает.
Тренажёр: 600 вопросов, мок с таймером, план повторов
senior·base — что спрашивают на самом деле
В этом посте были ссылки, но мы их удалили по правилам Сетки