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

MySQL RR 级别 + FOR UPDATE 能否解决 Write Skew 问题?串行化可以解决吗?

  •  
  •   lhx2008 · 2020-03-02 14:02:14 +08:00 · 1177 次点击
    这是一个创建于 1728 天前的主题,其中的信息可能已经有所发展或是发生改变。
    Write Skew 我的理解是这样的一个程序:

    if (select xxx 满足某个条件 X){
    do xxx 让条件 X 不满足;
    }

    在两个事务里面并发执行,并且在 do 之前条件是满足的。这样 do xxx 可能会执行一次,也可能会是两次。我们的要求是只能执行一次。


    对于已存在的行,select 用 FOR UPDATE 可以阻塞住第二个并发的 select,RC 和 RR 都不会出现 Write Skew 问题
    对于不存在的行,用 FOR UPDATE 无法挂行锁,RC 级别会出问题。RR 级别有间隙锁,有一些 do xxx 可能会因为间隙锁而造成死锁,最后只能执行一个事务,也可能间隙锁挂的位置不对而没有产生约束力(比如覆盖索引),从而 do 还是执行了两次,是这样的吗?

    另外,MySQL 的 串行化 似乎问题也同样存在,而 ddia 里面则说串行化可以解决,是我哪里理解错了?
    6 条回复    2020-03-02 15:41:47 +08:00
    chenset
        1
    chenset  
       2020-03-02 14:54:35 +08:00   ❤️ 1
    类似的问题我是用动态用 RC + FOR UPDATE 解决的 , 不知道你的为什么又问题. 不太确定你跟场景是否一致
    lhx2008
        2
    lhx2008  
    OP
       2020-03-02 14:56:30 +08:00
    @chenset #1 如果行已经存在是可以的,如果行不存在,比如 count 一个条件是不是 = 0,是的话插一条让他不等于 0,就有可能插到两条。
    chenset
        3
    chenset  
       2020-03-02 14:58:49 +08:00   ❤️ 1
    FOR UPDATE 无法挂行锁: 对了我不是 row 锁, 而是 range 锁. 是不是这个概念不太清楚了,太久了. 反正锁定的是多行共用同值的索引, 而不是唯一锁
    chenset
        4
    chenset  
       2020-03-02 15:00:07 +08:00   ❤️ 1
    我的场景是针对同一个商品抢购, 通过合计抢购明细达到不超售的目的. RR 没法解决 转而使用 RC
    FaceBug
        5
    FaceBug  
       2020-03-02 15:25:42 +08:00   ❤️ 1
    超卖问题不应该由数据库解决吧,考虑下 redis 之类的

    实在要数据库解决,可以锁商品行,扣减余额字段,同时增加订单

    而不是锁订单范围吧
    chenset
        6
    chenset  
       2020-03-02 15:41:47 +08:00
    @cepczkd 楼主可能不是超售的场景, 简单的 sql 就能解决超售问题我就没有的引入太多功能. 锁金额 /数量增加了一个字段, 综合考虑起来后就这样了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2744 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 11:37 · PVG 19:37 · LAX 03:37 · JFK 06:37
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.