InnoDB的锁(Locking)

mysql5.7关于innodb锁的官方文档

常见锁类型

  1. 共享锁(Shared)和排他锁(Exclusive)
  2. 意向锁(Intention)
  3. 记录锁
  4. 间隙锁
  5. 下一键锁

共享锁和排他锁

InnoDB实现标准的行级锁定,其中有两种类型的锁: 共享(S)锁和排他(X)锁。

  • 一个共享(S)锁允许持有锁的事务读取行级数据。

  • 一个独占(X)锁允许持有锁的事务更新或删除行级数据。

如果事务T1r行上持有S锁,则来自其他不同的事务T2 的对r行进行锁定的请求将按以下方式处理:

  • 事务T2用于S锁的请求可以立即被授予。其结果是,T1T2 共同持有r行的S锁。

  • 事务T2用于X锁不能立即授予。

如果某个事务T1r行上拥有一个独占(X)锁,则不能立即授予其他不同事务T2r行的任一类型的锁的请求。相反,事务T2必须等待事务T1释放对r行的锁定。

意向锁

InnoDB支持多种粒度锁定,允许行锁和表锁并存。例如,诸如在指定表上[LOCK TABLES ... WRITE]的语句采用排他锁(X锁)。为了使在多个粒度级别上的锁定变得切实可行,InnoDB使用意向锁来实现。意向锁是表级锁定,指示事务稍后对表中的行需要哪种类型的锁(共享锁或排他锁)。意向锁有两种类型:

  • 意向共享锁(IS)指示一个事务打算设置在一个表中一行或多行上的(S)锁。

  • 意向排他锁(IX)指示一个事务打算设置在一个表中一行或多行上的(X)锁。

例如,SELECT ... LOCK IN SHARE MODE设置一个IS锁,而SELECT ... FOR UPDATE设置一个IX锁。

意向锁协议如下:

  • 在事务可以获取表中某行上的共享锁之前,它必须首先获取该表上的IS锁或更高级别的锁。

  • 在事务可以获取表中某行的排他锁之前,它必须首先获取 该表上的IX锁。

表级锁类型的兼容性汇总在以下矩阵中。可以把列看作是其他事务已经被授予的锁,行是事务要新请求的锁。

X IX S IS
X 冲突 冲突 冲突 冲突
IX 冲突 兼容 冲突 兼容
S 冲突 冲突 兼容 兼容
IS 冲突 兼容 兼容 兼容

如果一个锁与现有锁兼容,则将其授予请求的事务,但如果与现有锁冲突,则不授予该锁。事务会一直等待直到冲突的现有锁被释放。如果锁定请求与现有锁发生冲突,并且由于会导致死锁而无法被授予许可 ,则会发生错误。

意向锁除全表请求以外(例如:LOCK TABLES ... WRITE)不会阻塞任何表或行。意图锁的主要目的是表明某人正在锁定表中的行或要锁定表中的行。

对于意图锁的事务数据会出现类似于在下面SHOW ENGINE INNODB STATUS和 InnoDB的监视器输出中:

TABLE LOCK table `test`.`t` trx id 10080 lock mode IX

记录锁

记录锁定是对索引记录的锁定。例如, SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE; 可以防止其它任何t.c1=10的事务进行插入,更新或删除。

记录锁始终锁定索引记录,即使没有定义索引的表也是如此。在这种情况下,请 InnoDB创建一个隐藏的聚集索引,并将该索引用于记录锁定。请参见 “聚集索引和二级索引”

对于记录锁的事务数据会出现类似于在以下SHOW ENGINE INNODB STATUS和 InnoDB的监视器输出中:

RECORD LOCKS space id 58 page no 3 n bits 72 index `PRIMARY` of table `test`.`t`
trx id 10078 lock_mode X locks rec but not gap
Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
 0: len 4; hex 8000000a; asc     ;;
 1: len 6; hex 00000000274f; asc     'O;;
 2: len 7; hex b60000019d0110; asc        ;;

间隙锁

间隙锁是对索引记录之间的间隙的锁定单/多索引间隙锁),或者是对第一个索引记录之前或最后一个索引记录之后的间隙的锁定(间隙锁)。例如,由于该范围内所有现有值之间的间隙被锁定,因此SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 FOR UPDATE;可以防止其他事务将value15插入column中t.c1,无论该列 中是否已经存在任何此类值。

间隙可能跨越单个索引值,多个索引值,甚至为空。

间隙锁是性能和并发性之间权衡的一部分,并且使用在某些事务隔离级别而非其他级别中。

对于使用唯一索引来锁定唯一行来锁定行的语句,不需要间隙锁定。(这不包括搜索条件仅包含多列唯一索引的某些列的情况;在这种情况下,会发生间隙锁定。)例如,如果该id列具有唯一索引,则以下语句仅使用一个具有id值100的行的索引记录锁定,其他会话是否在前面的间隙中插入行并不重要:

SELECT * FROM child WHERE id = 100;

如果id未索引或索引不唯一,则该语句会锁定前面的间隙。

在这里还值得注意的是,可以通过不同的事务将冲突的锁保持在间隙上。例如,事务A可以在间隙上保留一个共享的间隙锁(间隙S锁),而事务B可以在同一间隙上保留排他的间隙锁(间隙X锁)。允许冲突的间隙锁的原因是,如果从索引中清除记录,则必须合并由不同事务保留在记录上的间隙锁。

间隙锁定InnoDB是“纯粹抑制性的”,这意味着它们的唯一目的是防止其他事务插入间隙。间隙锁可以共存。一个事务进行的间隙锁定不会阻塞另一事务对相同的间隙进行间隙锁定。共享和排他间隙锁之间没有区别。它们彼此不冲突,并且执行相同的功能

间隙锁定可以显式禁用。如果将事务隔离级别更改为READ COMMITTED或启用 innodb_locks_unsafe_for_binlog 系统变量(现在已弃用),则会发生这种情况 。在这种情况下,将禁用间隙锁定来进行搜索和索引扫描,并且间隙锁定仅用于外键约束检查和重复键检查。

使用READ COMMITTED隔离级别或启用innodb_locks_unsafe_for_binlog 还具有其他效果 。MySQL评估WHERE条件后,将释放不匹配行的记录锁。对于 UPDATE语句,InnoDB 执行“半一致”读取,以便将最新的提交版本返回给MySQL,以便MySQL可以确定行是否与的WHERE 条件匹配UPDATE

下一键锁

下一键锁是索引记录上的记录锁定和索引记录之前的间隙上的间隙锁定的组合

InnoDB执行行级锁定的方式是,当它搜索或扫描表索引时,会在遇到的索引记录上设置共享或互斥锁。因此,行级锁实际上是索引记录锁。索引记录上的下一键锁定也会影响该索引记录之前的“间隙”。即,下一键锁定是索引记录锁定加上索引记录之前的间隙上的间隙锁定。如果一个会话R在索引中的记录上具有共享或排他锁 ,则另一会话不能R在索引顺序之前的间隙中插入新的索引记录 。

假设索引包含值10、11、13和20。该索引的可能的下一键锁定涵盖以下间隔,其中,圆括号表示排除区间端点,方括号表示包括端点:

(negative infinity, 10]
(10, 11]
(11, 13]
(13, 20]
(20, positive infinity)

对于最后一个间隔,下键锁锁定在上面的索引的最大值和间隙“确界” 具有比在索引实际上任何值高的值的伪记录。最高不是真正的索引记录,因此,实际上,此下一键锁定仅锁定跟随最大索引值的间隙。

默认情况下,InnoDBREPEATABLE READ事务隔离级别运行。在这种情况下,请InnoDB使用next-key锁定进行搜索和索引扫描,这可以防止幻像行(请参见第14.7.4节“幻像行”)。

用于下一个键锁定事务数据出现类似于在下面SHOW ENGINE INNODB STATUSInnoDB的监视器 输出:

RECORD LOCKS space id 58 page no 3 n bits 72 index `PRIMARY` of table `test`.`t`
trx id 10080 lock_mode X
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
 0: len 8; hex 73757072656d756d; asc supremum;;

Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
 0: len 4; hex 8000000a; asc     ;;
 1: len 6; hex 00000000274f; asc     'O;;
 2: len 7; hex b60000019d0110; asc        ;;

插入意图锁

插入意图锁是一种通过INSERT行插入之前的操作设置的间隙锁 。此锁发出插入意图的信号是,如果多个事务未插入间隙中的相同位置,则无需等待彼此插入的多个事务。假设有索引记录,其值分别为4和7。单独的事务分别尝试插入值5和6,在获得插入行的排他锁之前,每个事务都使用插入意图锁来锁定4和7之间的间隙,但不要互相阻塞,因为行是无冲突的。

下面的示例演示了在获得对插入记录的排他锁之前,使用插入意图锁的事务。该示例涉及两个客户端A和B。

客户端A创建一个包含两个索引记录(90和102)的表,然后启动一个事务,该事务将排他锁放置在ID大于100的索引记录上。排他锁在记录102之前包括一个间隙锁:

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

mysql> START TRANSACTION;
mysql> SELECT * FROM child WHERE id > 100 FOR UPDATE;
+-----+
| id  |
+-----+
| 102 |
+-----+

客户B开始交易以将记录插入空白。事务在等待获得排他锁的同时获取插入意图锁。

mysql> START TRANSACTION;
mysql> INSERT INTO child (id) VALUES (101);

用于插入意图锁定事务数据出现类似于在下面 SHOW ENGINE INNODB STATUSInnoDB的监视器 输出:

RECORD LOCKS space id 31 page no 3 n bits 72 index `PRIMARY` of table `test`.`child`
trx id 8731 lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 3 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
 0: len 4; hex 80000066; asc    f;;
 1: len 6; hex 000000002215; asc     " ;;
 2: len 7; hex 9000000172011c; asc     r  ;;...

自动上锁

一个AUTO-INC锁是通过交易将与表中取得一个特殊的表级锁 AUTO_INCREMENT列。在最简单的情况下,如果一个事务正在向表中插入值,则任何其他事务都必须等待自己在该表中进行插入,以便第一个事务插入的行接收连续的主键值。

innodb_autoinc_lock_mode 配置选项控制用于自动增加锁定的算法。它使您可以选择如何在可预测的自动增量值序列与插入操作的最大并发性之间进行权衡。

有关更多信息,请参见 第14.6.1.6节“ InnoDB中的AUTO_INCREMENT处理”

空间索引的谓词锁

InnoDB支持SPATIAL 包含空间列的列的索引(请参见 第11.4.8节“优化空间分析”)。

要处理涉及SPATIAL索引的操作的锁定 ,下一键锁定不能很好地支持支持REPEATABLE READSERIALIZABLE事务隔离级别。多维数据中没有绝对排序概念,因此不清楚哪个是 “下一个”键。

为了支持具有SPATIAL索引的表的隔离级别 ,请InnoDB 使用谓词锁。甲SPATIAL索引包含最小外接矩形(MBR)值,因此, InnoDB通过设置用于查询的MBR值的谓词锁强制上的索引一致的读取。其他事务不能插入或修改将匹配查询条件的行。

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