TomVista
V2EX  ›  问与答

没有锁,事务,如何保证+1 操作

  •  
  •   TomVista · Dec 3, 2020 · 2874 views
    This topic created in 1996 days ago, the information mentioned may be changed or developed.

    订单表里有个字段 count, 表示用户的第几个订单

    在没有锁,事务的前提下,

    新增订单的时候怎么保证 count 是正确的.

    不要问为啥没有锁和事务,问就祭天,

    Supplement 1  ·  Dec 3, 2020

    支持事务,

    但是事务的隔离级别未知,

    事务内部上下文隔离

    select count form ;
    
    insert count ; // 这里拿不到上一句的count
    
    

    好像用处不太大

    Supplement 2  ·  Dec 4, 2020
    所有的数据库操作都是在前端使用 http 进行请求,所以有些后端能用的东西,到这里就不合适了,
    目前看到的队列和唯一索引比较合适,

    乐观锁和 cas, 因为 count 需要前端额外查询一遍,也没办法保证业务的正确性
    39 replies    2020-12-04 17:11:24 +08:00
    konar
        1
    konar  
       Dec 3, 2020
    if (insertSucceeded)
    set count = count + 1
    konar
        2
    konar  
       Dec 3, 2020
    @konar 哦 count 在订单表不是用户表啊,那忽略吧
    oott123
        3
    oott123  
       Dec 3, 2020 via Android   ❤️ 2
    unique(user_id, count)
    这样至少不会重复
    TomVista
        4
    TomVista  
    OP
       Dec 3, 2020
    @oott123

    这个可行,

    select count(*) form order where order.user = user;

    insert count to order;

    大不了冲突几次,反正都没有事务 锁了,

    我这里是能执行数据库语句的,然后写个文档备注一下.

    感谢老哥,如果没有更好的方案就这个了
    duwan
        5
    duwan  
       Dec 3, 2020
    串行执行被
    tabris17
        6
    tabris17  
       Dec 3, 2020   ❤️ 1
    user,count 加唯一索引
    TomVista
        7
    TomVista  
    OP
       Dec 3, 2020
    @duwan

    我这里 请求部分 只能做到,发个 request, 等着 response, 没有办法串行. 条件不允许.
    haoz1w0w
        8
    haoz1w0w  
       Dec 3, 2020
    非要用 count 么 用插入时间倒排不就算出来了
    haoz1w0w
        9
    haoz1w0w  
       Dec 3, 2020
    哦 是正排
    fish267
        10
    fish267  
       Dec 3, 2020
    放 redis? 我瞎说的
    tabris17
        11
    tabris17  
       Dec 3, 2020
    还有个笨办法,分两步操作:

    先 insert,count 字段留空;
    然后再 update orderTab set count=(select count(*) from orderTab where user_id=? and id<=?) where id=?
    TomVista
        12
    TomVista  
    OP
       Dec 3, 2020
    @haoz1w0w emm,不合适

    insert order

    select count

    update order_count

    这个好像不太保准,有小概率,count 丢失,然后回滚和异常处理,目前这个技术栈也没法处理,unique(user_id, count) 要稳妥,方便
    TomVista
        13
    TomVista  
    OP
       Dec 3, 2020
    @fish267 不行,就我一个菜鸡,绝不给自己增加工作量
    TomVista
        14
    TomVista  
    OP
       Dec 3, 2020
    @tabris17

    #12

    这个不太妥
    zzzmh
        15
    zzzmh  
       Dec 3, 2020
    我一直用 update table set count = count + 1
    不过据说也不是最稳的
    Immortal
        16
    Immortal  
       Dec 3, 2020
    这不是乐观锁就可以实现的么
    TomVista
        17
    TomVista  
    OP
       Dec 3, 2020
    @Immortal 选技术栈做不到锁,就很尴尬,还有一个半残的事务机制,
    yao978318542
        18
    yao978318542  
       Dec 3, 2020
    redis 队列
    tabris17
        19
    tabris17  
       Dec 3, 2020 via iPhone
    @TomVista 两步走是最稳妥的方法,唯一索引插入冲突还要做异常处理,更加麻烦
    redtea
        20
    redtea  
       Dec 3, 2020
    这个字段存数据库有什么用?我感觉显示时可以实时算出来。
    退货、交易关闭场景考虑到了没有。
    Immortal
        21
    Immortal  
       Dec 3, 2020   ❤️ 1
    @TomVista #17
    建议查询下乐观锁在数据库中的应用
    TomVista
        22
    TomVista  
    OP
       Dec 3, 2020
    @Immortal 确实可行
    summertimesad
        23
    summertimesad  
       Dec 3, 2020   ❤️ 1
    试试无锁思想:CAS?

    `update xx set count = count + 1 where id = xxx count = excepted_count`
    如果 update 行数不等于 1, 重试该动作,直到成功
    TomVista
        24
    TomVista  
    OP
       Dec 3, 2020
    @tabris17 我的想法是 唯一冲突 后,报个网络错误,然后用户重新点一次
    TomVista
        25
    TomVista  
    OP
       Dec 3, 2020
    @redtea 和订单的自增 id 一起生成 订单的 流水号
    TomVista
        26
    TomVista  
    OP
       Dec 3, 2020
    @rambo92 我搞不定这个
    TomVista
        27
    TomVista  
    OP
       Dec 3, 2020
    @rambo92 我这边每次数据库改动都是一个 http 请求 , 我仔细研究了一下,我这个场景不合适用这个,
    sampeng
        28
    sampeng  
       Dec 3, 2020 via iPhone
    扔队列,消费者交叉执行。始终只有一个人在 insert 或者 update
    cxshun
        29
    cxshun  
       Dec 3, 2020
    没有锁的情况下只有用 CAS 了,先查询原 count,再更新 count 的同时判断目前的 count 是不是等于之前的 count 。
    wellsc
        30
    wellsc  
       Dec 3, 2020 via iPhone
    Cas,跳表,日志数据库
    SethShi
        31
    SethShi  
       Dec 3, 2020 via Android
    这不明显是用乐观锁吗😮
    summertimesad
        32
    summertimesad  
       Dec 3, 2020 via Android
    @TomVista 和是否 http 请求无关啊。
    TomVista
        33
    TomVista  
    OP
       Dec 4, 2020 via Android
    @rambo92 那可能我理解错了,我再看看
    Immortal
        34
    Immortal  
       Dec 4, 2020
    “乐观锁和 cas, 因为 count 需要前端额外查询一遍,也没办法保证业务的正确性”
    select for update
    老哥知识面还有待拓宽
    summertimesad
        35
    summertimesad  
       Dec 4, 2020
    "所有的数据库操作都是在前端使用 http 进行请求,所以有些后端能用的东西,到这里就不合适了,
    目前看到的队列和唯一索引比较合适,

    乐观锁和 cas, 因为 count 需要前端额外查询一遍,也没办法保证业务的正确性"

    大家都散了吧。。。
    TomVista
        36
    TomVista  
    OP
       Dec 4, 2020
    @Immortal 明白了,我后续再去看看,哪里理解错了
    haoz1w0w
        37
    haoz1w0w  
       Dec 4, 2020
    @TomVista 我的意思是实时计算
    TomVista
        38
    TomVista  
    OP
       Dec 4, 2020
    @haoz1w0w 场景不允许

    count 目前只用于生成订单号, 订单号有检索需求,比如 cms 中的订单查找
    PiersSoCool
        39
    PiersSoCool  
       Dec 4, 2020
    单机
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   2881 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 76ms · UTC 05:14 · PVG 13:14 · LAX 22:14 · JFK 01:14
    ♥ Do have faith in what you're doing.