Непоследовательность транзакции: запись в БД и отправка HTTP‑запроса

В условии неточность: при работающем @Transactional HTTP-вызов обычно идёт до commit, а не после него. Однако откат БД не отменяет уже выполненное действие внешней системы.

Короткий ответ

Что ответить на собеседовании

В условии неточность: при работающем @Transactional HTTP-вызов обычно идёт до commit, а не после него. Однако откат БД не отменяет уже выполненное действие внешней системы.

Подробный разбор

Ответ с пояснениями

Условие

В примере показан код, который сохраняет вычисленное значение в базу данных и сразу после этого пытается отправить его во внешнюю систему через HTTP‑запрос. Операция выглядит атомарной, однако реальная атомарность нарушается: запись в БД происходит в рамках транзакции, а сетевой запрос выполняется уже после её завершения. При падении сетевого вызова запись уже зафиксирована, и система может оказаться в неконсистентном состоянии.

@Transactional
public void calculate(GetFilesInfoRequest request) {
    double divisor = 6.85;
    double commissionRate = 5.2534;
    double result = (count * commissionRate) / divisor;

    repo.save(result);

    try {
        // HTTP POST
        notifier.sendCalculate(result);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

Задача — обсудить, почему такой подход не гарантирует атомарность, какие могут возникнуть проблемы и как их решить (например, использовать двухфазную фиксацию, outbox‑pattern, компенсационные транзакции и т.п.).

Ответ

В условии неточность: при работающем @Transactional HTTP-вызов обычно идёт до commit, а не после него. Однако откат БД не отменяет уже выполненное действие внешней системы.

Если HTTP завершился успешно, но commit затем не удался, внешний эффект останется без записи в БД. Timeout также не доказывает, что получатель ничего не сделал. Практический вариант — записать result и outbox-событие в одной транзакции, затем отправлять его отдельно с retry и идемпотентным ключом. Обычный HTTP endpoint не участвует в двухфазном commit автоматически. Обёртка исключения в RuntimeException обеспечивает откат стандартной Spring-транзакции, но не распределённую атомарность.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее