You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在每次交易后显示总金额?该总金额应采用什么方式存储?

虚拟币交易记录累计余额展示方案对比

方案1:新增TotalAmount字段预存累计余额

  • 优势:查询时直接返回字段即可,无额外计算开销,不管是分页查询还是全量导出交易记录性能都拉满,也不需要处理分页场景下的跨页累计逻辑。
  • 并发问题解决方案:可通过数据库原子操作完全规避,不需要在应用层做复杂的并发控制。以MySQL为例,插入交易时可以用带行锁的INSERT ... SELECT原子语句实现累计余额计算:
INSERT INTO transaction (UserId, ChangeInBalance, Created, TotalAmount)
SELECT 5, -3, NOW(), COALESCE(MAX(TotalAmount), 0) + (-3)
FROM transaction
WHERE UserId = 5
FOR UPDATE;

上述语句会先锁定对应用户的所有交易记录计算最新余额,再执行插入,全程原子性,不会出现并发插入导致的余额计算错误。

  • 适用场景:交易量大、查询频率高、对查询性能要求严苛的生产级金融业务场景。

方案2:实时计算累计余额

分为两种实现方式,均不需要修改现有表结构:

  1. 数据库层用窗口函数计算(MySQL 8.0+/PostgreSQL均支持),查询时直接生成累计余额:
SELECT 
    Id, UserId, ChangeInBalance, Created,
    SUM(ChangeInBalance) OVER (PARTITION BY UserId ORDER BY Created ASC, Id ASC) AS TotalAmount
FROM transaction
WHERE UserId = 5
ORDER BY Created ASC, Id ASC
LIMIT 0,10;
  1. 应用层计算:分页查询到当前页的交易列表后,先查询当前页第一条交易之前的所有余额变动总和作为初始值,再遍历当前页的每条记录累加得到每条的累计余额。
  • 优势:无数据冗余,不需要处理插入时的并发逻辑,开发成本极低,单用户交易记录在10万条以内、单页查询条数不超过100条时性能完全够用。
  • 劣势:当单用户交易记录超过10万条时,窗口函数计算耗时会明显上升,应用层计算也需要多一次历史余额查询的IO开销。

其他可选方案

如果已经做了冷热数据分离,可以把归档的冷交易记录的累计余额直接固化存储,近3个月的热数据用实时计算的方式,兼顾性能和存储成本,没有特殊需求不建议采用,会额外增加系统复杂度。

选型建议

  • 交易插入QPS低于1000、单用户交易记录普遍在10万条以内:优先选窗口函数实时计算的方案,不需要改表,逻辑最简洁
  • 交易查询频率极高、单用户交易记录普遍超过10万条:选预存TotalAmount的方案,用原子插入语句即可解决并发问题,是目前主流金融系统的通用实现

内容的提问来源于stack exchange,提问作者Vladyslav Kalashnikov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 23:12:01