Хранить балансы пользователей в поле DECIMAL в MySQL — плохая идея. Объясняю почему и как правильно.
Проблема 1: конкурентные обновления. Два запроса одновременно читают баланс $100 и оба пытаются списать $80. Без правильной блокировки оба успешны — вы уходите в минус.
Проблема 2: нет аудит-трейла. Вы не знаете, из каких транзакций сложился текущий баланс. При расхождении — ручная проверка сотен записей.
Проблема 3: денормализация. Сумма из таблицы transactions расходится с полем balance в таблице accounts — и непонятно, какому верить.
Правильный подход — double-entry ledger:
— Каждая операция создаёт две записи: дебет и кредит
— Баланс = SUM(credits) - SUM(debits) для счёта
— Счёт никогда не обновляется — только добавляются записи
— Для скорости: материализованный баланс обновляется после каждой транзакции в рамках одной DB-транзакции
Оптимистичная блокировка через version field или SELECT FOR UPDATE для критичных операций.
Для PostgreSQL есть хорошие open-source схемы: Monex, ledger-ruby как референс. Изучите их архитектуру перед тем как писать своё.
Интеграция платежных решений
@payment_integration_ops_arb
Хранить балансы пользователей в поле DECIMAL в MySQL — плохая идея. Объясняю почему и как правильно.
Этот пост опубликован в Telegram-канале Интеграция платежных решений. Подписаться можно по ссылке: @payment_integration_ops_arb.