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

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

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

而不是锁订单范围吧
chenset
2020-03-02 15:41:47 +08:00
@cepczkd 楼主可能不是超售的场景, 简单的 sql 就能解决超售问题我就没有的引入太多功能. 锁金额 /数量增加了一个字段, 综合考虑起来后就这样了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/649085

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX