Mysql中的锁

6 篇文章 0 订阅
1 篇文章 0 订阅

14.7.1 InnoDB的锁

本节介绍InnoDB使用的锁类型。

1、共享和独占锁 Shared and Exclusive Locks

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

  • 共享(S)锁允许持有该锁的事务读取行。
  • 独占(X)锁允许持有该锁的事务更新或删除行。

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

  • T2S锁的请求可以立即被批准。结果,T1T2都在r上保持S锁。
  • T2X锁的请求不能立即被批准。

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

2、意向锁 Intention Locks

InnoDB支持多粒度锁定,允许行锁和表锁共存。例如,诸如 LOCK TABLES…WRITE 之类的语句对指定的表使用独占锁(X锁)。为了实现多粒度级别的锁定,InnoDB使用了意向锁。意向锁是表级锁,用于指示事务稍后对表中的行需要哪种类型的锁(共享锁或独占锁)。意向锁有两种类型:

  • 意向共享锁IS)表示事务打算在表中的各行上设置共享锁。
  • 意向独占锁IX)表示事务打算在表中的各行上设置独占锁。

例如,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 STATUSINNODB 监视器 输出中显示如下:

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

3、记录锁 Record Locks

记录锁是索引记录上的锁。例如,SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE; 防止任何其他事务插入、更新或删除t.c1值为10的行。

记录锁始终锁定索引记录,即使表定义时没有索引。对于这种情况,InnoDB创建一个隐藏的聚集索引,并使用该索引进行记录锁定。参见第14.6.2.1节“聚类和二级索引”

记录锁的事务数据在 SHOW ENGINE INNODB STATUSINNODB 监视器 输出中显示如下:

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

4、间隙锁 Gap Locks

间隙锁是对索引记录之间间隙的锁,或对第一个索引记录之前或最后一个索引记录之后间隙的锁。例如,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中的间隙锁是“纯抑制性的”,这意味着它们的唯一目的是防止其他事务插入间隙。间隙锁可以共存。一个事务获取的间隙锁不会阻止另一个事务在同一间隙上获取间隙锁。共享和独占间隙锁没有区别。它们彼此不冲突,并且执行相同的功能。

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

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

5、下一个键锁 Next-Key Locks

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

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

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

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

对于最后一个间隔,下一个键锁锁定索引中最大值以上的间隙,以及值高于索引中任何实际值的“上确界”伪记录。上确界不是真正的索引记录,因此,实际上,下一个键锁只锁定最大索引值之后的间隙。

默认情况下,InnoDBREPEATABLE READ 事务隔离级别运行。在这种情况下,InnoDB使用下一个键锁进行搜索和索引扫描,这可以防止出现幻影行(参见 第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        ;;

6、插入意向锁 Insert Intention Locks

插入意向锁是在行插入之前通过 insert 操作设置的一种间隙锁。这种锁定表示插入的意图,即如果插入到同一索引间隙的多个事务没有插入到间隙内的同一位置,则它们不需要等待彼此。假设存在值为47的索引记录。尝试分别插入值为56的单独事务,在获得插入行的独占锁之前,每个事务都会使用插入意向锁锁定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监视器 输出中显示如下:

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

7、AUTO-INC锁 AUTO-INC Locks

AUTO-INC锁是一种特殊的表级锁,由插入到具有 AUTO_INCREMENT 列的表中的事务使用。在最简单的情况下,如果一个事务正在向表中插入值,那么任何其他事务都必须等待自己向该表进行的插入操作,以便第一个事务插入的行接收连续的主键值。

innodb_autoinc_lock_mode 变量控制用于自动增量锁定的算法。它允许您选择如何在可预测的自动增量值序列和插入操作的最大并发性之间进行权衡。

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

8、空间索引的谓词锁 Predicate Locks for Spatial Indexes

InnoDB支持对包含空间数据的列进行空间索引(参见 第11.4.8节“优化空间分析” )。

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值