本文基于mysql 8.0,官方手册: ,同时参考了
主要内容如下:
如果事务t1在r行持有s锁,则来自某些不同事务t2的对r行锁定的请求将按以下方式处理:
如果事务t1在r行拥有独占(x)锁,则不能立即批准某个不同事务t2对r上任一类型的锁的请求。相反,事务t2必须等待事务t1释放对r行的锁定。
注:共享锁之间不互斥,简记为:读读可以并行。排他锁与任何锁互斥,简记为:写读,写写不可以并行。
innodb支持多种粒度锁定,允许行锁和表锁并存。例如,lock tables ... write这样的语句在特定表上采用排他锁(x锁)。为了使在多个粒度级别上的锁定变得切实可行,innodb使用意图锁。意向锁是表级锁,指示事务稍后对表中的行需要哪种类型的锁(共享锁或排他锁)。有两种类型的意图锁:
例如,select ... for share设置is锁, select ... for update设置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
记录锁始终锁定索引记录,即使定义的表没有索引。对于这种情况,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 ;;
间隙可能跨越单个索引值、多个索引值,甚至可能为空。
间隙锁是性能和并发性之间权衡的一部分,并且被用于某些事务隔离级别,而不是其他级别。
使用唯一索引搜索唯一行的锁定语句不需要间隙锁。例如,如果id列有一个唯一的索引,下面的语句只对 id 值为100的行使用一个索引记录锁,其他会话是否在前面的间隙中插入行并不重要:
select * from child where id = 100;
如果 id 没有被索引或具有非唯一的索引,则语句将锁定前面的间隙。
这里还值得注意的是,冲突锁可能由不同的事务在一个间隙上持有。例如,事务a可以对间隙持有共享间隙锁(gap s-lock) ,而事务b对同一间隙持有排他间隙锁(gap x-lock)。 允许使用冲突的间隙锁的原因是,如果从索引中清除记录,则必须合并不同事务在记录上持有的间隙锁。
innodb中的间隙锁是“完全禁止的”,这意味着它们的唯一目的是防止其他交易插入到间隙中。间隙锁可以共存。一个事务获取的间隙锁并不阻止另一个事务获取同一间隙的间隙锁。 共享间隙锁和独占间隙锁之间没有区别。它们之间没有冲突,而且它们执行相同的功能。
可以显式禁用间隙锁。如果您将事务隔离级别更改为read committed,就会发生这种情况。 在这些情况下,搜索和索引扫描禁用间隙锁,并且仅用于外键约束检查和重复键检查。
使用 read committed 隔离级别还有其他影响。 在 mysql 评估 where 条件之后,将释放不匹配行的记录锁。 对于 update 语句,innodb 执行“半一致(semi-consistent)”读操作,以便将最新提交的版本返回给 mysql,这样 mysql 就可以确定该行是否符合 update 的 where 条件。
邻键锁是索引记录上的记录锁和索引记录前的间隙锁的组合。
innodb执行行级锁定的方式是,当它搜索或扫描表索引时,它会在遇到的索引记录上设置共享锁或排他锁。 因此,行级锁实际上是索引记录锁。索引记录上的邻键锁也会影响该索引记录之前的“间隙”。也就是说,邻键锁是索引记录锁加上索引记录前的间隙锁。 如果一个会话对索引中的记录r有一个共享或排他锁,那么另一个会话就不能按索引顺序在紧靠r的间隙中插入新的索引记录。
假设一个索引包含值10、11、13和20。该索引可能的邻键锁覆盖以下区间,其中圆括号表示排除了间隔端点,方括号表示包含端点:
(negative infinity, 10] (10, 11] (11, 13] (13, 20] (20, positive infinity)
对于最后一个间隔,邻键锁定索引中最大值以上的空隙,并锁定“上确界”伪记录的值高于索引中实际的任何值。上确界不是真正的索引记录,因此实际上,这个邻键锁只锁定最大索引值之后的空隙。
默认情况下,innodb 在 repeatable read 事务隔离级别运行。在这种情况下,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 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 ;;
下面的示例演示在获取所插入记录的独占锁之前使用插入意向锁的事务。这个例子涉及到两个客户端,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 ;;...
该innodb_autoinc_lock_mode 配置选项控制用于自增锁的算法。它允许您选择如何在可预测自增值序列与插入操作的最大并发性之间进行权衡。
innodb 支持对包含空间列的列进行 spatial 索引。
为了处理与 spatial 索引有关的操作的锁定,邻键锁定不能很好地支持 repeatable read 或 serializable 事务隔离级别。 多维数据中没有绝对排序概念,因此不清楚哪个是邻键。
为了支持具有 spatial 索引的表的隔离级别,innodb使用谓词锁。空间索引包含最小外接矩形值,因此 innodb 通过在用于查询的 mbr 值上设置谓词锁来强制对索引进行一致性读。 其他事务不能插入或修改与查询条件匹配的行。
如对本文有疑问, 点击进行留言回复!!
MySQL-关系代数-并、交、差、等值连接、自然连接、左连接。。。
网友评论