InnoDB加锁分析

17.3 about s sex

innodb锁类型

  • Share and Exclusive Locks(共享与排它锁)
  • Intention Locks(意向锁)
  • Record Locks (记录锁)
  • Gap Locks(间隙锁)
  • Next-Key Locks
  • Insert Intention Locks(插入意向锁)
  • AUTO-INC Locks(自增锁)
  • Predicate Locks for Spatial Indexes

Share and Exclusive Locks

Innodb的行锁有两种类型,即S锁与X锁

  • S锁:允许持有锁的事务去读取一行数据,显式加S锁:
    SELECT ... LOCK IN SHARE MODE
  • X锁:允许持有锁的事务去修改一行数据,显式加X锁:SELECT ... LOCK FOR UPDATE

S锁与S锁互相兼容,X锁与X、S锁均不兼容。意思是假如事务T1持有行A的S锁,事务T2申请行A的S锁时可以立即获取,而申请X锁时则不能立刻获取。如果事务T1持有行A的X锁,那么其他事务对行A申请的S、X锁均不能立刻获取

Intention Locks

使用意向锁实现锁的多粒度(行粒度与表粒度),刚才说的X与S属于行级锁,那么意向锁则属于表级锁。表明事务要对表中的某些行使用X锁与S锁,所以意向锁也有2中类型

  • IS锁:意味着要对表中某些行设置S锁
  • IX锁:意味着要对表中某些行设置X锁
    在获取一个行的S锁之前,必须先获取IS锁,在获取一个行的X锁之前,必须先获取IX锁
    意向锁不会阻塞除了全表操作外的请求,他主要用作表明某个事务正在锁定或将要锁定表中的某些行

Record Locks

记录锁是索引记录上的锁,即行锁并不是直接锁记录,而是锁索引。


给记录5加record锁示意图

Gap Locks

锁定的是两条索引记录的间隙,或者是第一个索引之前,或者最后一个索引之后的间隙,所以又称间隙锁。Gap Lock的目的是为了阻止其他事务插入到间隙中。间隙锁可以共存。一个事务占用的间隙锁不会阻止另一个事务占用同一间隙上的间隙锁

给记录5加Gap锁

Next-key Lock

是一个索引记录锁加上在索引记录之前的间隙上的间隙锁,即Record Lock与Gap Lock的组合。


记录5加next-key lock

假设我们有如下索引记录,10,11,13,那么可能的next-key锁区间为
(-无穷,10],(10,11],(11,13],(13,+无穷)

Insert Intention Locks

是Gap Lock的一种,是在插入操作之前的间隙锁。主要作用在于,多个事务插入到相同的索引间隙中,如果它们不在间隙中的相同位置插入,就不需要相互等待。
假设有值为4和7的索引记录。有两个事务尝试分别插入5和6,每个事务都用插入意图锁锁定4和7之间的间隙,但不会彼此阻塞。

CREATE TABLE child (id int(11) NOT NULL, PRIMARY KEY(id)) ENGINE=InnoDB;
INSERT INTO child (id) values (90),(102);

START TRANSACTION;
SELECT * FROM child WHERE id > 100 FOR UPDATE;

START TRANSACTION;
INSERT INTO child (id) VALUES (101);
是否阻塞?

AUTO-INC Locks

自增锁,属于表级锁,用于生成自增ID。可以通过【innodb_autoinc_lock_mode】设置自增锁的模式,可以通过下面的文档来了解这个参数对于自增锁的影响。https://dev.mysql.com/doc/refman/8.0/en/innodb-auto-increment-handling.html

Predicate Locks for Spatial Indexes

用于空间索引上的锁,空间索引与传统B+树索引不相同,用处较少,暂不阐述

RR隔离级别加锁分析

了解了常见的锁结构,我们来分析下常见的SQL到底是如何加锁的,我们以MySQL默认隔离级别RR为例。

这里我们先开启下MySQL的锁信息监控
开启innodb锁监控信息:set GLOBAL innodb_status_output_locks=ON,开启之后我们就可以使用 SHOW ENGINE INNODB STATUS命令来查看语句的加锁信息了。
监控相关文档可以查看:https://dev.mysql.com/doc/refman/8.0/en/innodb-enabling-monitors.html

主键查询

表数据
  • 主键等值查询
start TRANSACTION;
select * from lock where id = 1 for update;

这里主键记录存在,并且主键具有唯一性,所以这里比较简单,只给记录1加Record X锁。

start TRANSACTION;
select * from lock where id = 3 for update;

和上面不同,这里查询的记录不存在,那么此时给哪些记录加什么锁?我们SHOW ENGINE INNODB STATUS来看一下

------------
TRANSACTIONS
------------
Trx id counter 22488
Purge done for trx's n:o < 22487 undo n:o < 0 state: running but idle
History list length 48
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 281479539002944, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 281479539002040, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 22487, ACTIVE 52 sec
2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 34554, OS thread handle 123145411301376, query id 1945591 localhost 127.0.0.1 root starting
show engine innodb status
TABLE LOCK table `test`.`lock` trx id 22487 lock mode IX
RECORD LOCKS space id 233 page no 3 n bits 72 index PRIMARY of table `test`.`lock` trx id 22487 lock_mode X locks gap before rec
Record lock, heap no 3 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 4; hex 00000004; asc     ;;
 1: len 6; hex 000000005797; asc     W ;;
 2: len 7; hex 210000035411f4; asc !   T  ;;
 3: len 4; hex 80000004; asc     ;;
 4: len 4; hex 80000004; asc     ;;

通过日志能够看到这里加的是Gap锁,那么这里其实是对id=4的记录上加了一个gap锁,为的是防止后续的语句插入id=3的记录,产生幻读

start TRANSACTION;
update lock set col1 = 3 where id = 3;

比较简单,更新不存在的行,不加锁

start TRANSACTION;
update lock set col1 = 1 where id = 1;

更新不包含索引列,在主键记录上加Record X锁。

start TRANSACTION;
update lock set index1 = 1 where id = 1;

更新不包含索引列,在主键记录上加Record X锁,还需要在索引列上加Record X锁

  • 主键范围查询
start TRANSACTION;
select * from `lock` where id >= 1 for update 

会对id=1的记录加X锁,对id=4,id=8以及记录上界supremum加Next-Key锁,这样做到阻塞其他事务对id>=1的加锁操作。

start TRANSACTION;
select * from `lock` where id <= 1 for update 

会对id=1的记录加X锁,对id=4,id=8加Next-Key锁,并且在判断id=4,8不符合记录后,虽然server层调用unlock_row,但对于RC隔离级别以上且没有设置innodb_locks_unsafe_for_binlog那么并不会释放锁。

start TRANSACTION;
update lock set col1=1 id >= 1

未更新索引列,加锁与加锁与上面SELECT… WHERE PK >= XX FOR UPDATE;一致。

start TRANSACTION;
update lock set index1=1 id >= 1

更新包含索引列。对主键id=1加X锁,index索引行加X锁,然后对c1=30,c1=40的主键行加next-key ,同时对应的index索引行加X锁,最后对表示记录上界的’supremum’加next-key

start TRANSACTION;
update lock set index1=1 id <= 4

对主键 in(1,4)加next-key ,同时对应的index索引行加X锁。然后对id=8加 next-key lock,因不满足条件,因此server层查询停止,但并不会释放id=8上的锁。

  • 唯一索引等值
SELECT … WHERE UK = XX FOR UPDATE

记录存在,索引记录加X锁,对应主键加X锁。记录不存在,为了禁止幻读,需要保证别的事务不能再插入值为XX的新记录。需要在比XX大的第一条记录上加gap锁,这里只对二级索引记录进行加锁,并不会对聚簇索引记录进行加锁。

  • 唯一索引范围
SELECT … WHERE UK >= 1 FOR UPDATE

那么会对索引行(假设index1为唯一索引) in (1, 4, 8)分别加next-key lock,对应主键行加X锁,同时对index1上’supremum’ record加next-key lock。

SELECT … WHERE UK <= 4 FOR UPDATE

和上面主键索引类似,这里会对索引上 in (1,4)加next-key lock,对对应的主键行加X锁,然后对index1=8加next-key lock,且并不会去释放。

UPDATE … WHERE UK >= XX;

未包含索引列时,等同上面指定走唯一索引的SELECT…FOR UPDATE语句加锁
包含索引列时,除了上述语句的加锁外,还会对相应索引列上的行加X锁。

UPDATE … WHERE UN <= 4;

更新未包含索引列
会对un索引上(1,4)加next-key lock,对对应的主键行加X锁。un=8对应的索引行和主键行也会加X锁,同时不会释放。
包含索引列
这里会对un索引上(1,4)加next-key lock,对对应的主键行和index2索引加X锁。对un=8加next-key lock,对应主键行加X锁,因不符合range条件,对index2不做操作不会加锁。

  • 非唯一索引等值
    SELECT … WHERE INDEX = 4 FOR UPDATE;
    会对index =4在索引上加next-key lock,对应主键加X锁,然后在下一条记录上加gap锁 。
UPDATE … WHERE INDEX = XX;

未包含索引列时与上述一致;
包含索引列时,除了上述锁,会对相应的索引行加X锁。

  • 不含索引列
SELECT * FROM WHERE col1  = 1 FOR UPDATE

这个比较简单,直接全表扫描,为主键记录加next-key 锁

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

推荐阅读更多精彩内容