[mysql] [innodb]14.7.1 InnoDB 锁

网友投稿 691 2022-05-29

InnoDB的行级锁,有两种类型: shared (S) locks 和exclusive (X) locks。

shared (S) lock 允许持有锁读取行的事务。

exclusive (X) lock 允许事务在更新或删除行时持有锁。

如果事务T1持有在行r持有共享锁,则事务T2 的对行锁定的请求r将按以下方式处理:

T2对S锁的请求可以立即被批准。结果,T1和T2都在r上保持S锁。

T2对X锁的请求不能立即被批准。

如果事务T1在行 r上持有独占(X)锁,则不能立即授予来自某些不同事务T2的请求,请求使用r 上的任一类型的锁。相反,事务T2 必须等待事务 T1 释放其行 r 上的锁。

意图锁  (Intention Locks)

InnoDB支持 多粒度 锁定,允许行锁和表锁共存。例如,诸如锁定表等LOCK TABLES ... WRITE 在指定的表上获取独占锁(X 锁)。为使在多个粒度级别锁定,InnoDB 使用意图锁。意图锁是表级锁,用于指示事务以后需要哪种类型的锁(共享或独占锁),用于表中的行。有两种类型的意向锁:

意向共享锁(IS) 表示事务打算对表中的单个行设置共享锁。

意向独占锁 (IX) 表示事务打算对表中的单个行设置独占锁。

例如,SELECT ... LOCK IN SHARE MODE 设置是锁定,并SELECT ... FOR UPDATE设置 IX 锁。

意图锁定协议如下:

在事务可以获取表中行上的共享锁之前,它必须首先获取IS 锁或表上的更强锁。

在事务可以获取表中行的独占锁之前,它必须首先获取表上的 IX锁。

表级锁类型兼容性总结如下矩阵。

[mysql] [innodb]14.7.1 InnoDB 锁

S

IS

冲突

冲突

冲突

冲突

冲突

兼容

冲突

兼容

S

冲突

冲突

兼容

兼容

IS

冲突

兼容

兼容

兼容

如果请求事务与现有锁兼容,则向请求事务授予锁;如果与现有锁冲突,则不授予请求事务。事务等待,直到释放冲突的现有锁。如果锁请求与现有锁冲突,并且由于会导致死锁而发生错误。

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

意向锁的事务数据与 以下通过SHOW ENGINE INNODB STATUS  及 InnoDB monitor 输出类似的:

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

记录锁(Record Locks)

记录锁是在索引上的锁。例如,从 t 中选择 c1,其中 c1 = 10 用于更新;防止任何其他事务插入、更新或删除 t.c1值为10的行。

记录锁始终锁定索引记录,即使定义表时没有索引。对于此类情况,InnoDB 创建一个隐藏的群集索引,并使用此索引进行记录锁定。参见Section 14.6.2.1, “Clustered and Secondary Indexes”。

记录锁如下所示:

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 ;;

间隔锁(Gap Locks)

间隔锁是索引记录之间间隔的锁,或在第一个索引记录之前或之后对间隔的锁。例如,从 t 中选择 c1,其中 c1 介于 10 和 20 之间进行更新;防止其他事务将值 15 插入列 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执行"semi-consistent"读取,以便它将最新的提交版本返回到 MySQL,以便 MySQL 可以确定行是否与 UPDATE 的 WHERE 条件匹配。

Next-Key Locks

Next-Key Locks 是索引记录上的记录锁和索引记录之前间断锁定的组合。

InnoDB 执行行级锁定的方式是,在搜索或扫描表索引时,它会在它遇到的索引记录上设置共享锁或独占锁。因此,行级锁实际上是索引记录锁。索引记录的Next-Key Locks 锁也会影响索引记录前的"间断"。也就是说,Next-Key Locks 是索引记录锁,外加索引记录之前间断的间断锁。如果一个会话在索引中对记录R 具有共享或独占锁,则另一个会话无法在索引顺序 R 之前在间断中插入新的索引记录。

假设索引包含值 10、11、13 和 20。此索引的可能Next-Key Locks涵盖以下间隔,其中圆形括号表示间隔终结点的排除,方括号表示包含终结点:

(negative infinity, 10]

(10, 11]

(11, 13]

(13, 20]

(20, positive infinity)

对于最后一个间隔,Next-Key Locks 锁定索引中最大值上方的间隔和"supremum"伪记录的值高于索引中实际值的任何值。supremum 不是真正的索引记录,因此,实际上,此 Next-Key Locks  仅锁定最大索引值之后的差距。

默认情况下,InnoDB 在 REPEATABLE READ 级别中运行。在这种情况下,InnoDB 使用Next-Key Locks进行搜索和索引扫描,从而防止幻行(see Section 14.7.4, “Phantom Rows”)。

Next-Key Locks :

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);

插入意图锁

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配置选项控制用于自动增量锁定的算法。它允许您选择如何在自动递增值的可预测序列和插入操作的最大并发性之间进行权衡。

有关详细信息,see Section 14.6.1.6, “AUTO_INCREMENT Handling in InnoDB”。

空间索引的谓词锁(Predicate Locks for Spatial Indexes)

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

要处理涉及SPATIAL索引的操作的锁定,下键锁定不能很好地支持可重复读取或可序列化事务隔离级别。多维数据中没有绝对排序概念,因此不清楚哪个是"下一个"键。

若要支持具有 SPATIAL 索引的表的隔离级别,InnoDB 使用谓词锁。SPATIAL 索引包含最小边界矩形 (MBR) 值,因此 InnoDB 通过设置用于查询的 MBR 值的谓词锁来强制索引上一致的读取。其他事务无法插入或修改与查询条件匹配的行。

MySQL 数据库

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:了解线程
下一篇:Docker - 官方GUI Kitematic
相关文章