V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
baiyuxiong
V2EX  ›  问与答

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

  •  
  •   baiyuxiong · 2020-04-22 16:16:48 +08:00 · 1698 次点击
    这是一个创建于 1670 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

    12 条回复    2020-04-24 07:50:32 +08:00
    libook
        1
    libook  
       2020-04-22 16:25:51 +08:00
    最精确的肯定是每次从数据库里求和,但要看你量级多大,会不会导致性能问题。

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

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

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

    一定要在更新 fee 时,校验 fee 是否为原值,否则可能出现并发问题。
    baiyuxiong
        12
    baiyuxiong  
    OP
       2020-04-24 07:50:32 +08:00
    @libook 666 这个方案感觉不错
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   960 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 22:43 · PVG 06:43 · LAX 14:43 · JFK 17:43
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.