关于 Tigshop 资金/积分字段设计的优化建议
从一次并发事故说起:为什么我建议把余额从 user 表里拆出去
本文是对 Tigshop 商城系统数据模型设计的一点探讨,起因是我们团队在二次开发中遇到的实际问题。写出来供官方团队和社区开发者参考,无意否定现有设计,纯属技术交流。
一、先说结论
建议将 user、shop、vendor 三张主表中的资金/积分类字段迁移至独立的账户表中。
涉及字段:
| 表 | 字段 |
|---|---|
| user | balance、frozen_balance、commission_balance、frozen_commission_balance、points、growth_points |
| shop | shop_money、frozen_money |
| vendor | vendor_money、frozen_money |
这不是说现有设计“错了”,而是随着业务发展,这种设计在高并发场景下会逐渐暴露问题。趁早调整,成本最低。
二、从一个真实场景说起
假设这样一个场景:
用户 A 在 App 上修改昵称,同时该用户正在下单支付。两个操作几乎同时发生。
按照 Tigshop 现有的代码逻辑(MyBatis-Plus updateById),修改昵称时会把 user 表的整行数据查出来再更新回去。如果下单支付先扣了余额,修改昵称的更新又把旧余额覆盖回去了。
扣款被“吞”了。
这不是理论分析,而是我们在压测中真实复现过的问题。
也许有人说:“改昵称的时候把余额字段置空,MyBatis-Plus 就不更新它了。”确实可以规避,但实际开发中,每个开发人员写代码的习惯不同,资金安全不能依赖于“每个人都记得正确传参”。
资金字段应该有独立的、统一的服务入口来管控,而不是躺在主表里被随意更新。
三、现有设计存在哪些问题
3.1 行锁竞争
资金、积分是高频更新字段,昵称、头像也是高频更新字段。它们在同一行上,UPDATE 互斥。
- 改昵称的请求阻塞了充值的请求
- 下单扣款的事务锁住了用户信息更新
3.2 字段覆盖丢失
(接第二部分的例子,此处略,前面已有详细描述)
3.3 事务范围过大
下单时需要同时扣余额、加积分、扣库存、更新店铺资金。user 表作为热点表被锁在整个事务中,响应时间越长,锁等待越严重。
3.4 表职责不单一
user 表现在承载了四种不同性质的资产:
- 余额(普通资产)
- 佣金(分销资产)
- 积分(权益资产)
- 成长值(等级资产)
新增任何一种资产类型(如红包、优惠券额度),只能继续往表里堆字段。长此以往,表结构将越来越臃肿,维护成本越来越高。
3.5 现有流水表已经做得很完善,只差最后一步
这里必须肯定一下:Tigshop 已经设计了 user_balance_log、account、vendor_account_log 三张流水表,字段完整、结构清晰,说明官方在资金安全方面是有意识的。
现在的情况是:流水表已经到位了,但余额还留在主表里。 只差把“当前余额”独立成账户表,整个资金模块就能彻底解耦。
4、最后
这个建议并非是否定 Tigshop 的现有设计——事实上,Tigshop 的流水表设计已经优于很多同类型产品。我们提出这个优化,是希望 Tigshop 在资金安全和高并发方向上走得更远、更稳。
一个好的资金模块,应该有清晰的边界:主表管身份,账户管资产,流水管明细。 三者各司其职,互不干扰,才能支撑起业务长期稳健的发展。
以上是我们团队在二次开发中积累的一点思考,分享出来供 Tigshop 官方和社区开发者参考。如有不准确之处,欢迎指正讨论。







