MySQL中一些不可思议的加锁情况

最近看了极客时间MySQL45讲,有些情况的加锁场景真的是颠覆我的认知,然后写下这篇文章分享一下,这篇文章的内容都是基于MySQL45讲的总结。首先是数据和表的初始化:

CREATE TABLE `t` (
`id` int(11) NOT NULL, `c` int(11) DEFAULT NULL, `d` int(11) DEFAULT NULL, PRIMARY KEY (`id`),
KEY `c` (`c`)
) ENGINE=InnoDB;
insert into t values(0,0,0),(5,5,5), (10,10,10),(15,15,15),(20,20,20),(25,25,25);

我使用的MySQL版本是5.7,可重复读的隔离级别下。先看一个小问题:

session A session B session C
begin;<br />select * from t where c>=15 and c<=20 order by c desc for update;
Insert into t values(11,11,11);
Insert into t values(6,6,6);

估计你一看会觉得这不是非常明显,我建议自己试一试,先不说答案,看完这篇文章你应该就知道为什么了。

先说一下MySQL加锁规律,总结起来就是下面几条:

  1. 加锁的基本单位是next-key lock。next-key lock是前开后闭区间.
  2. 查找过程中访问到的对象才会加锁。
  3. 索引上的等值查询,给唯一索引加锁的时候,next-key lock退化为行锁。
  4. 索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock退化为间隙锁。
  5. 唯一索引上的范围查询会访问到不满足条件的第一个值为止。

案例一:等值查询间隙锁

session A session B session C
begin;<br />update t set d = d+1 where id=7
insert into t values(8,8,8);<br />(block)
update t set d = d+1 where id=10
(ok)

我们按照上面总结的规律分析一下,7是在(5,10]这个区间内的,然后加锁区间是(5,10]然后是等值查询 next-key lock 退化间隙锁最终结果是(5,10)。

案例二:非唯一索引等值锁

session A session B session C
begin;<br />select id from t where c = 5 lock in share mode;
update t set d = d+1 where id=5
(ok)
insert into t values(7,7,7);<br />(block)

看到这个的时候我当时就是一句卧槽,这尼玛MySQL出bug了吧,这不是乱加锁,这。。。。我们按前面的几个规律分析一下。

一开始mysql会给c=5加一行读锁。加锁的单位是next-key lock,所以(0,5]。c是一个普通索引,MySQL在找到这条记录的时候并不能确定还有没其他的行,所以要继续查找,直到找到c=10,所以加锁的范围就是(5,10],类似于案例一,结果就是(0,5)间隙锁,c=5行锁,(5,10)间隙锁。分析到这里感觉很有成就感,但是为啥update t set d = d+1 where id=5执行成功了?只有查找到了的结果才会加锁,也就说这里的行锁是加了c=5,并不会锁id,这个查询使用覆盖索引,并不需要访问主键索引,所以主键索引上没有加任何锁。如果我们把session A的查询换成select * from t where c = 5 lock in share mode;查询的是所有而不是id,那么session B就会被阻塞,不信自己可以试试看。注意session A lock in share mode;如果换成 for update,系统会认为你接下来要更新数据,因此会顺便给主键索引上满足条件的行加上行锁。所以我们经常说的加锁是锁主键是有前提的。

案例三:主键索引范围锁

mysql> select * from t where id=10 for update;
mysql> select * from t where id>=10 and id<11 for update;

这两句sql是等价的吗?执行逻辑肯定是等价的,但是加锁逻辑是不一样的,select * from t where id=10 for update;主键等值查询 next-key lock 退化成行锁,就是加了id=10这条锁。对于 select * from t where id>=10 and id<11 for update; 首先找到id=10这一行加个行锁,11是在(10,15]间隙内的所以加锁逻辑就是(10,15],id=10的行锁即[10,15]。

案例四:非唯一索引范围锁

select * from t where c>=10 and c<11 for update;这种情况相比于案例三差不多,只是在找到c=10这行时不会退化成行锁,而是一个 next-key lock 所以结果(5,10],然后11在(10,15]区间内加上(10,15]。即(5,15]。

案例五:唯一索引范围锁

对应第五条规律,唯一索引上的范围查询会访问到不满足条件的第一个值为止。唯一索引讲道理找到了那一行应该就不会继续往下扫描的,事实上却不是。

session A session B session C
begin;<br />select id from t where id >10 and id<=15 for update;
update t set d = d+1 where id=20
(block)
insert into t values(16,16,16);<br />(block)

对于select id from t where id >10 and id<=15 for update; 首先加上(10,15] next-key lock,找到了15之后并不会停还会继续往下扫描,所有又会加上(15,20],就出现了表格中的情况。select id from t where id >=10 and id<=15 for update;这个加锁是怎么加的呢?答案是(5,10],(10,15],(15,20]。

案例六:非唯一索引上存在"等值"的例子

我们在刚刚的数据上加上

insert into t values(30,10,30);

这时候表里的索引c的数据就变为

c 0 5 10 10 15 20 25
Id 0 5 10 30 15 20 25

此时我们执行一条 select * from t where c=10 for update;加锁情况是怎么样的呢?

image-20200912145714893

(c=5,id=5)和(c=15,id=15)这两行上都没有锁。select * from t where c=10 for update limit 2;如果给这个查询上sql加个limit呢?

image-20200912150756175

就是少了一个间隙。

回到我们最开始那个问题,select * from t where c>=15 and c<=20 order by c desc for update;这条sql是怎么加锁的?首先找到c=15并要找到不满足条件的值也就是c=10加锁,加上一个next-key lock 也就是(5,10],20也是一样的道理找到c=20的不满足情况的一个值25加上next-key lock (20,25],最后的结果就是(5,10],(10,15],(15,20],(20,25]。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,125评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,293评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,054评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,077评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,096评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,062评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,988评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,817评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,266评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,486评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,646评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,375评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,974评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,621评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,642评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,538评论 2 352