V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
jtping
V2EX  ›  程序员

购物车结算问题

  •  1
     
  •   jtping · 2021-01-07 14:22:58 +08:00 · 2304 次点击
    这是一个创建于 1414 天前的主题,其中的信息可能已经有所发展或是发生改变。

    购物车结算生成订单时,需要对购物车中每件商品进行库存校验,和库存预扣除

    我现在想到了两种方案

    第一种:

    是每次只获取一个商品的锁,然后查询判断库存,预扣除,然后释放锁,之后的商品都走一遍这个流程

    第二种:

    是一次性获取到所有需要结算的商品的锁,然后一次性查询出所有商品库存,进行库存判断,预扣除,然后释放所有的锁

    两种方法目前我能想到的利弊:

    第一种如果商品多了,访问数据库就会比较频繁,但是锁单件商品的时间短了

    第二种如果商品多了,访问数据库虽然不会很频繁,但锁持有的时间肯定比第一种方法要长(而且是所有需要结算商品的锁)

    哪种方法比较合适,或者有什么更好的方法

    希望各位大神指导指导

    12 条回复    2021-01-08 16:23:51 +08:00
    kop1989
        1
    kop1989  
       2021-01-07 14:29:54 +08:00
    从我的经验上,我推荐用第二种。
    因为真正的业务场景比你设想的要复杂。
    1 、有商品组合(套装)的可能。
    2 、有消费者凑单的可能。
    3 、有二级库的可能。
    jtping
        2
    jtping  
    OP
       2021-01-07 14:37:41 +08:00
    @kop1989 多谢指导 目前我也比较倾向第二种 但一次性持的锁过多会不会对后面等待的用户不太友好
    Mitt
        3
    Mitt  
       2021-01-07 14:42:05 +08:00
    @jtping #2 我没做过这类的,不过我觉得可以考虑把库存缓存到 redis 了,等真正订单处理完成后再同步到数据库里,这样你的锁代价就很低了
    kop1989
        4
    kop1989  
       2021-01-07 14:46:31 +08:00   ❤️ 1
    @jtping #2 这就要看你真正的业务需求(也就是预计的网站流量、商品规模而定)
    比如像京东这种庞然巨物,就需要同时支持消费者“如果 A 没了,那我就不要 B,但保留 C”,“如果 A 没货,我就不买了”,“A 没了,我依然要买其他”,“ABC 是个套装,我用了个套装优惠券”等需求。

    这时候如果你选择第一种,在数据链路层来卡死只锁单件商品,就会面临频繁的锁》扣库》释放》异常》锁》退库》释放。
    这时候造成的系统性能浪费未见得更低,以及会带来业务展现上的不稳定(消费者会面临这款产品的库存数量“频繁抖动”)。也增加了上层的业务实现复杂度。
    jtping
        5
    jtping  
    OP
       2021-01-07 14:53:17 +08:00
    @Mitt 多谢指导 我之前一直在考虑两种方法的利弊 没往这方面想
    jtping
        6
    jtping  
    OP
       2021-01-07 14:56:47 +08:00
    @kop1989 豁然开朗! 是我之前没考虑周全
    YouLMAO
        7
    YouLMAO  
       2021-01-07 19:10:50 +08:00
    jd, ali 都是 TCC 分布式事务, 不是数据库加锁的
    YouLMAO
        8
    YouLMAO  
       2021-01-08 00:40:35 +08:00 via Android
    如果 A 没了,那我就不要 B,但保留 C”,“如果 A 没货,我就不买了”,“A 没了,我依然要买其他 @kop1989 京东阿里哪个页面是这个逻辑?不符合中国人原理
    pinews
        9
    pinews  
       2021-01-08 10:22:50 +08:00
    小白来交流下,减库存这个操作,本身不就自带锁吗,第一种和第二种有什么区别?第二种怎么减少数据库访问了?不同的商品可以一块减?
    就算有区别,锁的总耗时没较少,也说不上增加吧,问题应该是解决总耗时吧。

    要解决总耗时只能用缓存数据库了啊,redis memcached mysql 的 memory 表都可以吧,

    另外如果处理订单除了减库存,还要减红包,发短信,发邮件,赠送积分,红包等等,那可以考虑协程异步处理(消息队列)了啊

    不知道说的对不对。
    jtping
        10
    jtping  
    OP
       2021-01-08 15:40:40 +08:00
    @pinews 假设购物车一次性结算 100 件商品

    第一种方法就要执行 100 遍 update 语句来更新每件商品的库存 每件商品执行一次 但每次只需要拿一件商品的锁

    第二种方法将 100 件商品库存用一个 update 语句更新 因为需要一起更新 所以就需要同时持有 100 件商品的锁

    大概是这么个意思
    pinews
        11
    pinews  
       2021-01-08 16:16:51 +08:00
    @jtping 如果所有商品减库存都是相同的,比如-1,的确可以一起 update,明白了

    那就考虑缓存数据库呗,期待你的结果。
    jtping
        12
    jtping  
    OP
       2021-01-08 16:23:51 +08:00
    @pinews
    哈哈其实不必都相同 批量 update 网上一找一大堆

    我目前用的是第二种方案 利弊上面也有大神说了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3017 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 13:08 · PVG 21:08 · LAX 05:08 · JFK 08:08
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.