MySQL 是怎么加行级锁的?为什么一会是 next-key 锁,一会是间隙锁,一会又是记录锁?

大家好,我是小林 。
是不是很多人都对 MySQL 加行级锁的规则搞的迷迷糊糊 , 一会是 next-key 锁,一会是间隙锁 , 一会又是记录锁 。
坦白说 , 确实还挺复杂的 , 但是好在我找点了点规律,也知道如何如何用命令分析加了什么类型的行级锁 。
之前我写过一篇关于「MySQL 是怎么加行级锁的?」的文章,随着我写 MySQL 锁相关的文章越来越多时,后来发现当时的文章写的不够详细 。
为了让大家很清楚的知道 MySQL 是怎么加行级锁的 , 以及如何用命令分析加了什么行级锁,所以我重写了这篇文章 。
文章内容比较长,大家可以耐心看下去,一定会有新的发现!
什么 SQL 语句会加行级锁?InnoDB 引擎是支持行级锁的,而 MyISAM 引擎并不支持行级锁 , 所以后面的内容都是基于 InnoDB 引擎 的 。
普通的 select 语句是不会对记录加锁的,因为它属于快照读,是通过 MVCC(多版本并发控制)实现的 。
如果要在查询时对记录加行级锁,可以使用下面这两个方式,这两种查询会加锁的语句称为锁定读 。
//对读取的记录加共享锁(S型锁)select ... lock in share mode;//对读取的记录加独占锁(X型锁)select ... for update;上面这两条语句必须在一个事务中,因为当事务提交了,锁就会被释放,所以在使用这两条语句的时候 , 要加上 begin 或者 start transaction 开启事务的语句 。
**除了上面这两条锁定读语句会加行级锁之外,update 和 delete 操作都会加行级锁,且锁的类型都是独占锁(X型锁)** 。
//对操作的记录加独占锁(X型锁)updaet table .... where id = 1;//对操作的记录加独占锁(X型锁)delete from table where id = 1;共享锁(S锁)满足读读共享,读写互斥 。独占锁(X锁)满足写写互斥、读写互斥 。

MySQL 是怎么加行级锁的?为什么一会是 next-key 锁,一会是间隙锁,一会又是记录锁?

文章插图
行级锁有哪些种类?不同隔离级别下 , 行级锁的种类是不同的 。
在读已提交隔离级别下,行级锁的种类只有记录锁 , 也就是仅仅把一条记录锁上 。
在可重复读隔离级别下,行级锁的种类除了有记录锁,还有间隙锁(目的是为了避免幻读),所以行级锁的种类主要有三类:
  • Record Lock,记录锁 , 也就是仅仅把一条记录锁上;
  • Gap Lock,间隙锁,锁定一个范围 , 但是不包含记录本身;
  • Next-Key Lock:Record Lock + Gap Lock 的组合,锁定一个范围,并且锁定记录本身 。
接下来 , 分别介绍这三种行级锁 。
Record LockRecord Lock 称为记录锁,锁住的是一条记录 。而且记录锁是有 S 锁和 X 锁之分的:
  • 当一个事务对一条记录加了 S 型记录锁后,其他事务也可以继续对该记录加 S 型记录锁(S 型与 S 锁兼容),但是不可以对该记录加 X 型记录锁(S 型与 X 锁不兼容);
  • 当一个事务对一条记录加了 X 型记录锁后,其他事务既不可以对该记录加 S 型记录锁(S 型与 X 锁不兼容),也不可以对该记录加 X 型记录锁(X 型与 X 锁不兼容) 。
举个例子 , 当一个事务执行了下面这条语句:
mysql > begin;mysql > select * from t_test where id = 1 for update;事务会对表中主键 id = 1 的这条记录加上 X 型的记录锁,这样其他事务就无法对这条记录进行修改和删除了 。
MySQL 是怎么加行级锁的?为什么一会是 next-key 锁,一会是间隙锁,一会又是记录锁?

文章插图
img
当事务执行 commit 后,事务过程中生成的锁都会被释放 。
Gap LockGap Lock 称为间隙锁,只存在于可重复读隔离级别 , 目的是为了解决可重复读隔离级别下幻读的现象 。
假设,表中有一个范围 id 为(3,5)间隙锁,那么其他事务就无法插入 id = 4 这条记录了,这样就有效的防止幻读现象的发生 。
MySQL 是怎么加行级锁的?为什么一会是 next-key 锁,一会是间隙锁,一会又是记录锁?

文章插图
img
间隙锁虽然存在 X 型间隙锁和 S 型间隙锁,但是并没有什么区别,间隙锁之间是兼容的,即两个事务可以同时持有包含共同间隙范围的间隙锁,并不存在互斥关系,因为间隙锁的目的是防止插入幻影记录而提出的 。
Next-Key LockNext-Key Lock 称为临键锁,是 Record Lock + Gap Lock 的组合,锁定一个范围,并且锁定记录本身 。

推荐阅读