7)InnoDB加锁案例分析

前面分析过MySQL的锁分类方式,MyISAM仅支持表锁,不支持行锁,所以不需要做过多分析。这篇文章就针对InnoDB分析一下加锁的案例。

创建一个表student,带有字段id,name,age,address,其中id是主键,name是唯一索引,age是普通索引,address没有索引。

初始化数据
mysql> select * from student;
+----+-------+-----+---------+
| id | name  | age | address |
+----+-------+-----+---------+
|  1 | gary  |  30 | suzhou  |
|  2 | kerry |  30 | nantong |
+----+-------+-----+---------+
2 rows in set (0.00 sec)

非索引项的锁升级表锁

在session 1里面查询address = 'nantong'的记录,并加上排他锁。

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from student where address = 'nantong' for update;
+----+-------+-----+---------+
| id | name  | age | address |
+----+-------+-----+---------+
|  2 | kerry |  30 | nantong |
+----+-------+-----+---------+
1 row in set (0.00 sec)

session 2里面去更新id = 1的age字段。

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update student set age = 10 where id = 1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

可以看到的行为是整个表都被锁住了。
结论:
|-- 非索引条件加锁会变成表锁。

间隙锁和Next-Key lock

除了行锁和表锁之外,InnoDB引入间隙锁,为了解决RR隔离级别下的不可重复读带来的幻读问题。
当使用范围条件查询而不是等值条件查询的时候,InnoDB就会给符合条件的范围索引加锁,在条件范围内不存在的记录就叫做“间隙”。
这里已经排除了非索引项的可能性,那么下面就需要讨论几个方面问题:
普通索引项是否会加间隙锁?
范围查询是否会加间隙锁?
唯一索引和主键索引是否会加间隙锁?
不存在的检索条件是否会加间隙锁?

再开始之前准备的数据

mysql> select * from student;
+----+-------+-----+---------+
| id | name  | age | address |
+----+-------+-----+---------+
|  1 | gary  |   1 | suzhou  |
|  2 | kerry |   5 | nantong |
|  5 | gary1 |  10 | sz      |
|  6 | test  |  15 | nt      |
|  7 | test1 |  20 | sz      |
+----+-------+-----+---------+
5 rows in set (0.00 sec)
Next-Key lock会在age字段分间隙 (-&,1], (1,5], (5,10], (10,15], (15,20], (20,+&)
普通索引项
  1. 通过普通索引,查询一个不存在的索引值,比如12,落在(10,15]的范围内,因为12不存在所以不会加行锁,那么间隙锁的范围就是(10,15)。
session 1
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from student where age = 12 for update;
Empty set (0.00 sec)

session 2
mysql> update student set address = 'teest' where id = 5;  --age=10
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
mysql> update student set address = 'teest' where id = 6; --age=15
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
mysql> insert into student(name,age,address) values ('test2', 11, 'sz');
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert into student(name,age,address) values ('test2', 14, 'sz');
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

可以看到age为10和15的行并没有锁,可以更新成功,而age为11和14的值是insert失败的。
结论:
|-- RR级别下,普通索引未命中,会加gap lock。
|-- RC级别,不存在Gap lock,所以不会加锁

  1. 通过普通索引,查询一个存在的索引值,比如15,落在(10,15]的范围内,这个时候就是锁定的(10, 20)。
mysql> update student set address = 'teest' where id = 5; -- age=10
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
mysql> update student set address = 'teest' where id = 6;  -- age=15
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> update student set address = 'teest' where id = 7; -- age=20
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
mysql> insert into student(name,age,address) values ('test2', 11, 'sz');
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert into student(name,age,address) values ('test2', 19, 'sz');
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

可以看到age为10和20的行是没有锁的,更新成功,而10和20之间都不能做更新和插入。
结论:
|-- RR级别下,普通索引命中,普通索引会加next-key lock,聚簇索引加X锁
|-- RC级别,对普通索引和聚簇索引都加X锁

唯一索引项
  1. 通过唯一索引,查询一个不存在的索引值,与普通索引类似。
    结论:
    |-- RR级别下,唯一索引未命中,只会在唯一索引加gap lock
    |-- RC级别,不存在Gap lock,所以不会加锁

  2. 通过唯一索引,查询存在的索引值,这里不会再加gap lock了,都会退化成record lock。
    结论:
    |-- RR级别,对唯一索引和聚簇索引都加X锁
    |-- RC级别,对唯一索引和聚簇索引都加X锁

聚簇索引
  1. 查询未命中
    |-- RR级别下,聚簇索引加gap lock
    |-- RC级别,不加锁
  2. 查询命中
    |-- RR级别下,聚簇索引加X锁
    |-- RC级别,聚簇索引加X锁

REFER:一个线上SQL死锁异常分析:深入了解事务和锁

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

推荐阅读更多精彩内容