开发中计算金额合计怎么算?

2020-04-22 16:16:48 +08:00
 baiyuxiong

需求是: 用户参与活动报名,缴报名费,每次有人报名后,活动总共收到的报名费就要统计出来。 方法 1: update table set fee = fee + 10

方法 2: $fee = "select sum(fee) from pay_log where ..." update table set fee = $fee

大家都用什么方法保证不出错? 方法 1 和方法 2 是不是都必须加上事务?

1552 次点击
所在节点    问与答
12 条回复
libook
2020-04-22 16:25:51 +08:00
最精确的肯定是每次从数据库里求和,但要看你量级多大,会不会导致性能问题。

还有就是总额是展示给用户看的还是展示给老板看的,一般展示给用户看都不是真实的数量或金额。
keepeye
2020-04-22 16:40:01 +08:00
用方法 1 ,和 pay_log 插入语句放到一个事务里
方法 2 怕并发
baiyuxiong
2020-04-22 16:40:51 +08:00
@keepeye 方法 1 总感觉可靠性低,担心算错。
baiyuxiong
2020-04-22 16:41:46 +08:00
@libook 如果量级大就选择方法 1 ?
keepeye
2020-04-22 17:02:56 +08:00
为什么担心算错?
hua123s
2020-04-22 17:03:01 +08:00
在可重复读隔离级别下,update 是当前读,所以 1 和 2 是等价。我刚刚百度的,不知道对不对
hua123s
2020-04-22 17:07:21 +08:00
看错,方法二不带 for update,方法二会脏读
mwiker
2020-04-22 17:09:54 +08:00
没缴纳时间吗?
libook
2020-04-22 18:11:37 +08:00
@baiyuxiong 并不是,只是说量大的话方案 2 性能会差,届时可能需要一些更复杂的方案来保障较强一致性的同时也能保障较高的可用性。

举个例子:
可以做两层,上层是快照层,用 Redis 等内存数据库来存当前的总额,又增加则在这个数字上直接累加;下层是持久层,记录每一条交易。
服务读取总额的时候只从快照层读取当前总额,然后可以设置一个对持久层性能影响较小的刷新周期,比如 10 秒,每个刷新周期从持久层计算总额然后覆盖到快照层。当然这个方案还要考虑业务级别的事务,比如对两层进行写操作需要有原子性,要么都写成功,要么都失败。

还可以更复杂,当然一切都是看实际情况,如果你量不大,没必要搞这么复杂,就每次求和就行了。
zhuangzijun1996
2020-04-22 22:55:10 +08:00
这种东西用户也不知道,有必要实时更新么。。
CStarter
2020-04-22 22:55:19 +08:00
update table set fee = fee + 10 where fee = 原值

一定要在更新 fee 时,校验 fee 是否为原值,否则可能出现并发问题。
baiyuxiong
2020-04-24 07:50:32 +08:00
@libook 666 这个方案感觉不错

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/665033

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX