InnoDB 锁

网友投稿 664 2022-11-03

本站部分文章、图片属于网络上可搜索到的公开信息,均用于学习和交流用途,不能代表睿象云的观点、立场或意见。我们接受网民的监督,如发现任何违法内容或侵犯了您的权益,请第一时间联系小编邮箱jiasou666@gmail.com 处理。

InnoDB 锁

本文翻译自 MySQL 官方文档

此文介绍 InnoDB 使用的锁类型:

  • 共享锁和独占锁

  • 意向锁

  • 记录锁

  • 间隙锁

  • Next-Key 锁

  • 插入意向锁

  • AUTO-INC 锁

  • 空间索引的谓词锁

共享锁和独占锁

InnoDB 实现了标准的行级锁,其中有两种类型的锁,共享锁(S)和独占锁(X)。

  • 共享锁允许持有锁的事务读取一行。

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

如果事务T1持有r行上的共享(S)锁,那么来自某个不同事务T2的请求对r行上的锁的处理如下:

  • T2对S锁的请求可以立即被批准。因此,T1和T2都对r保持S锁。

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

如果事务T1持有r行上的排他锁(X),那么某个不同事务T2对r上任意一种类型的锁的请求都不能立即被授予。相反,事务T2必须等待事务T1释放其对r行的锁。

意向锁

InnoDB支持多粒度锁,允许行锁和表锁共存。例如,一个语句,如 LOCK TABLES ... WRITE
接受指定表上的排他锁(X锁)。为了使多粒度级别的锁更实用,InnoDB使用了意向锁。意向锁是表级锁,它指示事务以后对表中的一行需要哪种类型的锁(共享锁或排他锁)。有两种类型的意图锁:

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

  • 意向排他锁(IX)表示事务打算对表中的各个行设置排他锁。

例如,SELECT...FOR SHARE
设置 IS 锁,SELECT...FOR UPDATE
设置 IX 锁。

意向锁协议如下:

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

  • 在事务获得表中一行的排他锁之前,它必须首先获得表上的 IX 锁。

表级锁类型兼容性总结如下:


XIXSIS
XConflictConflictConflictConflict
IXConflictCompatibleConflictCompatible
SConflictConflictCompatibleCompatible
ISConflictCompatibleCompatibleCompatible

如果一个锁与现有锁兼容,那么它将被授予一个请求事务,但如果它与现有锁冲突,则不会授予它。事务将等待,直到释放冲突的现有锁。如果锁请求与现有锁冲突,并且由于锁请求会导致死锁而不能授予锁,则会发生错误。意向锁不会阻塞任何东西,除了全表请求(例如,LOCK TABLES...WRITE )。意向锁的主要目的是表明某人正在锁定表中的一行,或准备锁定表中的一行。在 SHOW ENGINE INNODB STATUS 和 INNODB monitor 输出中,意向锁的事务数据类似如下: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 monitor 输出中,记录锁的事务数据类似如下: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 gapRecord 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)锁间隙锁是索引记录之间的间隙上的锁,或者是第一个索引记录之前或最后一个索引记录之后的间隙上的锁。例如,SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 For UPDATE;防止其他事务将值 15 插入列 t.c1 中,无论列中是否已经有这样的值,因为范围内所有现有值之间的间隙被锁定。一个间隙可以跨越一个索引值,多个索引值,甚至是空的。间隙锁是性能和并发性之间的折衷,用于某些事务隔离级别,而不适用于其他事务隔离级别。对于使用唯一索引锁定行以搜索唯一行的语句,不需要间隙锁定。(这不包括搜索条件只包括多列惟一索引的一些列的情况;在这种情况下,会发生间隙锁定。)例如,如果 id 列有一个唯一的索引,下面的语句只对id值为100的行使用一个索引记录锁,而其他会话是否在前面的间隙中插入行并不重要:SELECT * FROM child WHERE id = 100;如果id没有索引或有一个非惟一索引,语句会锁定前面的空白。这里还值得注意的是,不同的事务可以在一个间隙上持有冲突的锁。例如,事务 A 可以在一个间隙上持有一个共享间隙锁(间隙S -锁),而事务B在同一个间隙上持有一个排他间隙锁(间隙X -锁)。允许冲突间隙锁的原因是,如果从索引中清除了一条记录,则必须合并由不同事务持有的记录上的间隙锁。InnoDB 中的 Gap 锁是“纯抑制的”,这意味着它们的唯一目的是防止其他事务插入到 Gap 中。间隙锁可以共存。一个事务获得的间隙锁不能阻止另一个事务获得相同间隙上的间隙锁。共享和独占间隙锁之间没有区别。它们彼此不冲突,它们执行相同的功能。间隙锁定可以显式禁用。如果将事务隔离级别更改为 READ COMMITTED,就会发生这种情况。在这些情况下,间隙锁定对于搜索和索引扫描是禁用的,并且仅用于外键约束检查和重复键检查。使用 READ COMMITTED 隔离级别还有其他影响。不匹配行的记录锁在 MySQL 计算 WHERE 条件后被释放。对于 UPDATE 语句,InnoDB 执行一个“半一致”的读取,这样它会返回最新提交的版本给 MySQL,以便 MySQL 可以确定这行是否匹配 UPDATE 的WHERE条件。间隙锁是 InnoDB 为了解决在可重复读提交下产生的幻读问题。幻读的存在是因为新增或更新操作会导其它事务的范围查询(加锁查询)出现不一致的问题。Next-Key Locksnext-key lock是索引记录上的记录锁和索引记录之前间隙上的间隙锁的组合。InnoDB 执行行级锁的方式是这样的:当它搜索或扫描一个表索引时,它会对遇到的索引记录设置共享或排他锁。因此,行级锁实际上是索引记录锁。索引记录上的下一个键锁定也会影响该索引记录之前的“间隙”。也就是说,next-key 锁是一个索引记录锁加上一个间隙锁,该间隙位于索引记录之前。如果一个会话对一个索引中的记录R有一个共享或排他锁,那么另一个会话就不能在索引顺序R之前的间隙中插入一个新的索引记录。假设索引包含值10、11、13和20。这个索引可能的next-key锁包括以下时间间隔,其中圆括号表示不包含间隔端点,方括号表示包含端点:(负无穷大, 10](10, 11](11, 13](13, 20](20, 正无穷大)对于最后一个间隔,next-key 锁将锁定索引中最大值以上的间隙,并且“supremum”伪记录的值高于索引中实际的任何值。上界不是一个真正的索引记录,因此,实际上,这个 next-key 锁只锁住了最大索引值后面的间隙。默认情况下,InnoDB 运行在 REPEATABLE READ事务隔离级别。在这种情况下,InnoDB 使用 next-key 锁进行搜索和索引扫描,这就防止了幻像行(见后续文章)。在 SHOW ENGINE INNODB STATUS 和 INNODB monitor 输出中,next-key lock 的事务数据类似如下:RECORD LOCKS space id 58 page no 3 n bits 72 index `PRIMARY` of table `test`.`t`trx id 10080 lock_mode XRecord 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 STATUS 和 INNODB monitor 输出中,插入意图锁的事务数据类似如下: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 waitingRecord 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-INC 锁是一种特殊的表级锁,由插入到带有 AUTO_INCREMENT 列的表中的事务获得。在最简单的情况下,如果一个事务正在向表中插入值,那么任何其他事务都必须等待自己的插入操作,以便第一个事务插入的行接收连续的主键值。innodb_autoinc_lock_mode  配置选项控制用于自动增量锁定的算法。它允许您选择如何在自动增量值的可预测序列和插入操作的最大并发性之间进行权衡。有关更多信息,请参见之前 InnoDB 磁盘结构:表文章中有关自动增量一节 。空间索引的谓词锁InnoDB 支持对包含空间列的列进行空间索引。为了处理涉及 SPATIAL 索引的操作的锁,next-key 锁不能很好地支持 REPEATABLE READ 或 SERIALIZABLE 事务隔离级别。多维数据中没有绝对排序的概念,所以不清楚哪一个是“下一个”键。为了支持具有 SPATIAL 索引的表的隔离级别,InnoDB 使用谓词锁。SPATIAL 索引包含最小边界矩形(MBR)值,因此 InnoDB 通过在用于查询的 MBR 值上设置谓词锁来强制对索引进行一致的读取。其他事务不能插入或修改与查询条件匹配的行。

上一篇:软件测试培训之测试用例设计与管理思路整理简单7个步骤
下一篇:软件测试培训之基于“经验”的测试用例设计
相关文章

 发表评论

暂时没有评论,来抢沙发吧~