Корректное списание средств с пользовательского баланса

В UPDATE отсутствует WHERE — он меняет всех пользователей. Проверку достаточности баланса и списание нужно объединить в атомарную операцию.

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

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

В UPDATE отсутствует WHERE — он меняет всех пользователей. Проверку достаточности баланса и списание нужно объединить в атомарную операцию.

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

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

Условие

В системе есть таблица user, где хранится текущий остаток средств каждого пользователя. Представлена функция на псевдокоде, реализующая процесс снятия суммы с баланса. Необходимо проанализировать её, выявить проблемные места и предложить улучшения, учитывая, что код работает в продакшене. Особое внимание следует уделить вопросам конкурентного доступа, атомарности операций, использованию транзакций и возможным гонкам данных (race conditions).

func withdrawBalance(userID int32, amount float32) {
    balance = exec('select balance from user u where u.id=$1', userID)
    if balance - amount >= 0.0 {
        exec('update user u set balance=balance-$1', amount)
        return exec('select balance from user u where u.id=$1', userID)
    }
}

Ответ

В UPDATE отсутствует WHERE — он меняет всех пользователей. Проверку достаточности баланса и списание нужно объединить в атомарную операцию.

Деньги храните целыми минимальными единицами, не float32. Проверяйте amount > 0, валюту и допустимый диапазон. Для PostgreSQL базовая операция выглядит так:

UPDATE "user"
SET balance = balance - $2
WHERE id = $1 AND balance >= $2
RETURNING balance;

Ноль возвращённых строк означает, что списание не выполнено: пользователь отсутствует либо денег недостаточно. Предварительный SELECT не защищает от конкурентного списания. Если одновременно пишется журнал операций, используйте транзакцию и уникальный ключ идемпотентности: повтор HTTP-запроса не должен повторно снять деньги. Ошибки БД и результат RETURNING обязательно проверяются.

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

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

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

Подробнее