ENIGMA AI
ENIGMA AI

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

встречается 1× middle database

Как ответить

Баланс партнёра — это критически важные деньги, поэтому основное правило: никаких чисел с плавающей точкой. Используйте DECIMAL(18,2) или NUMERIC — они гарантируют точность до копейки. Второе правило: все операции с балансом должны быть атомарными и выполняться в транзакции. Никогда не читайте баланс в коде приложения, не меняйте его и не пишите обратно — это классический race condition.

Вместо этого делайте атомарный UPDATE с проверкой условия. Например, для списания:

BEGIN;
UPDATE partner_balances
SET balance = balance - 100.50
WHERE partner_id = 42 AND balance >= 100.50;

IF ROW_COUNT() = 0 THEN
    ROLLBACK;
    -- ошибка: недостаточно средств
ELSE
    INSERT INTO balance_operations (partner_id, amount, type, created_at)
    VALUES (42, -100.50, 'withdrawal', NOW());
    COMMIT;
END IF;

Такой подход исключает гонку: UPDATE блокирует строку (InnoDB row lock), а проверка balance >= 100.50 гарантирует, что мы не уйдём в минус. Журнал операций (balance_operations) обязателен — это аудит, возможность отката и восстановления. Каждая операция — отдельная запись с типом, суммой, временем и внешним ключом на партнёра.

Если нужна строгая консистентность (а для денег она нужна), используйте SELECT ... FOR UPDATE только когда логика сложнее простого UPDATE (например, нужно проверить несколько условий или агрегировать данные). Но в большинстве случаев атомарного UPDATE достаточно.

Для высоконагруженных систем можно применить шардинг по partner_id или партиционирование таблицы операций по дате — это ускорит запросы и упростит архивацию. Баланс самого партнёра лучше хранить в отдельной таблице с единственной строкой на партнёра и обновлять её только через UPDATE — никаких INSERT/UPDATE конфликтов.

И последнее: не используйте ORM для обновления баланса. ORM часто читает объект, меняет поле и пишет — это две операции вместо одной. Пишите прямые SQL-запросы или используйте хранимые процедуры.

Ключевые тезисы

  • Использовать DECIMAL/NUMERIC для точного хранения денежных сумм, никогда FLOAT/DOUBLE.
  • Атомарные UPDATE с условием (balance >= amount) для списаний — без чтения в коде приложения.
  • Обязательная транзакция: UPDATE баланса + INSERT в журнал операций для аудита.
  • Избегать ORM и SELECT + UPDATE в коде — это race condition.
  • Для высокой нагрузки — шардинг по partner_id и партиционирование таблицы операций.

Что спросят дальше

  • — Как обрабатывать отрицательный баланс, если по бизнес-логике он допустим (например, кредитный лимит)?
  • — Как вы тестируете конкурентные сценарии (параллельные списания) в автоматических тестах?
  • — Что делать, если таблица балансов стала узким местом при 10 млн партнёров и 1000 операций в секунду?

Готовьтесь к собеседованию с ENIGMA AI

AI-суфлёр подсказывает ответы прямо на собеседовании в реальном времени — незаметно для интервьюера.

Скачать приложение