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

PostgreSQL 并发问题:下单之前检查商品数量是否足够,如果足够则购买后数量递减

  •  
  •   TangMonk · 2016-06-01 14:04:51 +08:00 · 2010 次点击
    这是一个创建于 2897 天前的主题,其中的信息可能已经有所发展或是发生改变。

    用的默认的 Read Committed 并发控制,会不会出现多余的订单?

    比如说现在有 100 个订单,会不会出现 100+个订单?

    23 条回复    2016-06-03 17:42:20 +08:00
    ipconfiger
        1
    ipconfiger  
       2016-06-01 14:10:33 +08:00
    要用 Serializable 才行
    TangMonk
        2
    TangMonk  
    OP
       2016-06-01 14:16:40 +08:00
    @ipconfiger 读取数量和递减数量的时候都用 Serializable 吗?
    tabris17
        3
    tabris17  
       2016-06-01 14:22:55 +08:00
    update product set inventory=inventory-1 where product_id=123 and inventory>=1
    TangMonk
        4
    TangMonk  
    OP
       2016-06-01 14:24:28 +08:00
    @tabris17 默认就是这样的。。
    tabris17
        5
    tabris17  
       2016-06-01 14:38:03 +08:00
    @TangMonk 你是说先 select 出 inventory ,然后 update 语句里不判断 inventory ?那必须 Serializable 隔离级别或者加锁
    TangMonk
        6
    TangMonk  
    OP
       2016-06-01 14:43:22 +08:00
    @tabris17 恩,对,先 select 出数量,然后再 update, 并且没有判断数量>=1 。
    TangMonk
        7
    TangMonk  
    OP
       2016-06-01 14:44:25 +08:00
    @tabris17 今天出现了这个问题,系统预先设置了 1000 个库存,然后后台发现 1008 个订单。。但是商品的数量还是为 0 ,并没有为-8 。。
    tabris17
        8
    tabris17  
       2016-06-01 14:54:49 +08:00
    @TangMonk 如果是 set inventory=inventory-1 不会出现这种情况,除非你是 set inventory=?
    jjx
        9
    jjx  
       2016-06-01 15:01:52 +08:00
    版本机制

    或用队列

    最安全的就是队列+版本机制
    imzshh
        10
    imzshh  
       2016-06-01 15:05:18 +08:00
    关键词: select for update
    TangMonk
        11
    TangMonk  
    OP
       2016-06-01 15:05:52 +08:00
    @tabris17 的确,用的就是 set inventory=?
    TangMonk
        12
    TangMonk  
    OP
       2016-06-01 15:06:27 +08:00
    @imzshh 谢谢,我搜下
    TangMonk
        13
    TangMonk  
    OP
       2016-06-01 15:10:10 +08:00
    @imzshh FOR UPDATE 不会锁住 SELECT 吗?只会锁 UPDATE , DELETE 和 FOR UPDATE 吗?
    TangMonk
        14
    TangMonk  
    OP
       2016-06-01 15:13:09 +08:00
    FOR UPDATE 貌似要比 Serializable 好用点
    TangMonk
        15
    TangMonk  
    OP
       2016-06-01 15:21:51 +08:00
    @tabris17 为什么 set inventory=inventory-1 不会出现这种情况呢
    imzshh
        16
    imzshh  
       2016-06-01 15:21:52 +08:00
    @TangMonk 你自己做些测试吧,因为这个要配合事务一起用的,所以实现的时候要考虑的东西还挺多的,程序异常,死锁之类的。
    TangMonk
        17
    TangMonk  
    OP
       2016-06-01 15:27:23 +08:00
    @imzshh 好的,谢谢
    tabris17
        18
    tabris17  
       2016-06-01 15:29:52 +08:00
    @TangMonk 因为字段自减是原子操作
    TangMonk
        19
    TangMonk  
    OP
       2016-06-01 16:53:34 +08:00
    @tabris17 刚才我开了几个线程请求测试了下,貌似不行,库存为 1000 ,库存递减到 0 的时候,才生成了 500 多个订单。。。

    我换成 FOR UPDATE , 测试了下没有问题了。

    看来要得好好补习下 MVCC 了
    TangMonk
        20
    TangMonk  
    OP
       2016-06-01 16:54:29 +08:00
    @TangMonk 读和写的都用 FOR UPDATE 锁住了
    wdrsam
        21
    wdrsam  
       2016-06-03 15:36:35 +08:00
    握草,楼主你们是某软 11 级,前身 andware ,大神是薛大神的那个团队?
    TangMonk
        22
    TangMonk  
    OP
       2016-06-03 15:48:22 +08:00
    @wdrsam 是,你怎么知道?!你是?
    wdrsam
        23
    wdrsam  
       2016-06-03 17:42:20 +08:00
    @TangMonk 之前在这看到你们发的招聘, @andware 后缀就想起了,哈哈。我也是某软 11 级的
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3435 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 12:32 · PVG 20:32 · LAX 05:32 · JFK 08:32
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.