MySQL锁--03---意向锁(Intention Locks)间隙锁(Gap Locks)临键锁(Next-Key Locks)

Posted 高高for 循环

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL锁--03---意向锁(Intention Locks)间隙锁(Gap Locks)临键锁(Next-Key Locks)相关的知识,希望对你有一定的参考价值。

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


意向锁(Intention Locks)

需要强调一下,意向锁是一种不与行级锁冲突表级锁,这一点非常重要。

意向锁分为两种:

1)意向共享锁(IS锁):事务在请求S锁前,要先获得IS锁
2)意向排他锁(IX锁):事务在请求X锁前,要先获得IX锁

– 事务要获取某些行的 S 锁,必须先获得表的 IS 锁。

-- 事务要获取某些行的 S 锁,必须先获得表的 IS 锁。
SELECT column FROM table ... LOCK IN SHARE MODE;

– 事务要获取某些行的 X 锁,必须先获得表的 IX 锁。

-- 事务要获取某些行的 X 锁,必须先获得表的 IX 锁。
SELECT column FROM table ... FOR UPDATE;

意向锁是有数据引擎自己维护的,用户无法手动操作意向锁,在为数据行加共享 / 排他锁之前,InooDB 会先获取该数据行所在在数据表的对应意向锁。

为啥要有意向锁呢

innodb下有行锁,也有表级锁。

  • 如果事务A要给一张表加表写锁,肯定是不允许这张表有其他事务B已经在某行数据上加了行写锁的。那么mysql怎么去检索一张表里面的数据有没有行写锁啊,一条一条去看,是不是效率也太低了~
  • 所以这里衍生了意向锁。如果事务B对某行数据加了行写锁(属于排他锁哦),那么B也会同样给这张表加一个意向排他锁,等到事务A来加表锁的时候,事务A
    会看到这张表上有了意向排它锁,事务A就不再进行加锁操作了。

意向锁的兼容互斥性

1. 意向锁之间是互相兼容的

2. 意向锁不会与行级的共享 / 排他锁互斥!!!

3. 意向锁与普通的表级排他 / 共享锁互斥:


总结

  1. InnoDB 支持多粒度锁,特定场景下,行级锁可以与表级锁共存。
  2. 意向锁之间互不排斥,但除了 IS 与 S 兼容外,意向锁会与 共享锁 / 排他锁 互斥。
  3. IX,IS是表级锁,不会和行级的X,S锁发生冲突。只会和表级的X,S发生冲突。
  4. 意向锁在保证并发性的前提下,实现了行锁和表锁共存且满足事务隔离性的要求。

间隙锁(Gap Locks)

MySQL InnoDB支持三种行锁定方式:

  • 行锁(Record Lock)
    锁直接加在索引记录上面。
  • 间隙锁(Gap Lock)
    锁加在不存在的空闲空间,可以是两个索引记录之间,也可能是第一个索引记录之前或最后一个索引之后的空间。
  • 临键锁 ( Next-Key Lock )
    行锁与间隙锁组合起来用就叫做Next-Key Lock。

快照读 和 当前读

InnoDB的默认隔离级别RR(可重复读),在RR下读数据有两种方式:

1. 快照读:-mvcc

普通的 select… 查询都是快照读

mvcc — 基于版本的控制协议

  • 在MVCC下,事物开启执行第一个SELECT语句后会获取一个数据快照,直到事物结束读取到的数据都是一致的

2. 当前读: -next-key lock

读取的数据的最新版本,并且在读的时候不允许其它事物修改当前记录

临键锁(Next-Key Locks),也就是结合gap锁与行锁,

实现:

  1. 快照读(snapshot read)
    简单的select操作(不包括 select … lock in share mode, select … for update)

  2. 当前读(current read)
    select … lock in share mode、select … for update
    insert、update、delete

间隙锁概念:

当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,

  1. nnoDB会给符合条件的已有数据记录的索引项加锁;
  2. 对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁.

举例 1

假如user表中只有101条记录,其empid的值分别是 1,2,…,100,101,

select * from  user where user_id > 100 for update;
  • 是一个范围条件的检索,InnoDB不仅会对符合条件的user_id值为101的记录加锁,
  • 也会对user_id大于101(这些记录并不存在)的“间隙”加锁。

举例 2

这是在可重复读前提下,更有利于解决幻读的问题。如图:0,5,10,15,20,25这些数据之间的间隔 就是他们的间隙,而间隙锁就是 对他们这一部分空间进行加锁。

  • 而行锁就是对存在数据的锁,比如给5这条数据加锁,也就是锁住了5这一行数据。而行锁和间隙锁组合起来也就是 next-key lock.上面的数据 也就形成了7个间隙锁。
  • (-∞,0]、(0,5]、(5,10]、(10,15]、(15,20]、(20, 25]、(25, +supremum]。

InnoDB 使用间隙锁的目的

防止幻读

  • 上述案例,要是不使用间隙锁,如果其他事务插入了user_id大于100的任何记录,那么本事务如果再次执行select * from user where user_id > 100 for update;,就会发生幻读

RR隔离级别

当前读: 依靠next-key来解决幻读问题,

快照读: 使用mvcc解决幻读

案例1 :

建表innodb_lock:

DROP TABLE IF EXISTS `innodb_lock`;
CREATE TABLE `innodb_lock` (
  `a` int(10) NOT NULL,
  `b` varchar(255) NOT NULL DEFAULT '',
  KEY `index_a` (`a`),
  KEY `index_b` (`b`)
) ENGINE=InnoDB;

插入数据,注意这里边没有a为2的数据:

INSERT INTO `innodb_lock` VALUES ('1', 'b2');
INSERT INTO `innodb_lock` VALUES ('3', '3');
INSERT INTO `innodb_lock` VALUES ('4', '4000');
INSERT INTO `innodb_lock` VALUES ('5', '5000');
INSERT INTO `innodb_lock` VALUES ('6', '6000');
INSERT INTO `innodb_lock` VALUES ('7', '7000');
INSERT INTO `innodb_lock` VALUES ('8', '8000');
INSERT INTO `innodb_lock` VALUES ('9', '9000');

(1)开启两个客户端,修改事务隔离级别为可重复读


(2)开启事务,在左侧客户端批量修改a为1~6范围内的数据。在右侧客户端插入a为2的数据。右侧操作被阻塞。说明有间隙锁。

(3)重复(2),事务隔离级别依然是repeatable read,只不过变成在右侧客户端插入a为10的数据,成功。

(4)事务隔离级别设置为read committed,重复步骤(2),发现右侧客户端的操作成功。说明该隔离级别无间隙锁。


(5)还要特别说明的是,InnoDB除了通过范围条件加锁时使用间隙锁外,如果使用相等条件请求给一个不存在的记录加锁,InnoDB也会使用间隙锁!左侧客户端给不存在的记录加锁,右侧客户端的增加操作阻塞。

但是,如果a是唯一索引,不会升级全表锁。先添加唯一索引:

(6)重复步骤(5),发现右侧客户端不会被阻塞,数据插入成功

临键锁(Next-Key Locks)

行锁与间隙锁组合起来用就叫做Next-Key Lock。

加锁规则(RR隔离级别下)

1.原则

  • 原则1:加锁的基本单位是next-key lock。(是一个前开后闭的区间)
  • 原则2:查找过程中访问到的对象才加锁

2.优化

  • 优化1:唯一索引上的等值查询,匹配上时,给唯一索引加锁,next-key-lock会退化为行锁。

  • 优化2:索引上的等值查询,向右遍历且最后一个值不满足等值条件的时候,next-key-lock退化为 间隙锁 Gap Locks 。

  • 优化3:唯一索引和普通索引在范围查询的时候 都会访问到不满足条件的第一个值为止

案例 2 :


在上面的数据表我们可以得到5个next-key lock 区间:

  • 唯一索引(id):(-∞,1],(1,4],(4,6],(6,9] ,(9,+supremum]

  • 非唯一索引(age):(-∞,18],(18,21],(21,23],(23,26] ,(26,+supremum]

1.唯一索引等值查询:

当索引项存在时: next-key-lock会退化为行锁

当索引项不存在时: 向右遍历且最后一个值不满足等值条件的时候,next-key-lock退化为 间隙锁 Gap Locks

2. 唯一索引范围查询:

3. 非唯一索引等值查询:

4 .非唯一索引范围查询:

以上是关于MySQL锁--03---意向锁(Intention Locks)间隙锁(Gap Locks)临键锁(Next-Key Locks)的主要内容,如果未能解决你的问题,请参考以下文章

mysql innodb插入意向锁

MySQL锁的定义( 意向共享锁意向排他锁死锁)

MySQL锁的定义( 意向共享锁意向排他锁死锁)

MySQL锁的定义( 意向共享锁意向排他锁死锁)

Mysql中的锁:表MDL意向锁行锁

Mysql 死锁过程及案例详解之插入意向锁与自增锁备份锁日志锁Insert Intention Lock Auto-increment Lock Backup Lock Log Lock