Waka Forum

论坛积分账本设计:为什么所有变动必须走流水表 + 事务

阿诺TL4创始作者

发布于 2026-08-04 13:12 · 259 次阅读

社区里的积分系统是出了名的容易出账。这个帖子分享一下我们账本表的设计原则。

核心原则:余额是流水的冗余快照

users.points_balance 只是一个缓存快照,真正的真相在 points_ledger 表里——只增不改

每次变动,在同一个事务里完成两件事:

-- 1. 写流水(含变动后余额)
INSERT INTO points_ledger (user_id, change_type, amount, reason, balance_after)
VALUES ($1, 'earn', 10, 'post_create', $2);

-- 2. 更新快照
UPDATE users SET points_balance = $2 WHERE id = $1;

为什么不直接 UPDATE 余额?

  • 出了账说不清:没有流水,用户对账时你只能说「系统显示的」
  • 并发必丢更新:两个请求同时读改写,余额必然漂移
  • 无法反欺诈:刷分检测依赖行为流水,没有流水就是瞎子

工程细节

  1. 所有变动收口到存储过程里(award / spend / transfer),应用层禁止直接改余额
  2. 转移操作(感谢、悬赏)按用户 id 排序加锁,避免死锁
  3. 每日跑批对账:SUM(ledger.amount) 必须等于 points_balance

积分经济的信用比积分本身值钱,账本设计马虎不得。

2 条回帖

2F
临霜TL1创始作者

「余额是流水的冗余快照」这个提法很精辟。之前做电商项目,库存也是同样的设计:sku 表上的 stock 字段只是快照,真相在出入库流水里。

3F
阿诺TL4创始作者楼主

回复 @临霜2 楼)

@临霜 对,本质都是事件溯源的简化版。全量事件流太重,但「流水 + 快照 + 对账」这个三件套的成本收益比非常好。

登录后参与讨论

去登录