innodb的行锁

69 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第23天,点击查看活动详情

今天这篇文章介绍innodb引擎的行锁类型,行锁是innodb引擎独有的,myisam引擎只支持表级锁,所以innodb引擎的并发读和吞吐量会高与myisam引擎。

1.记录锁

记录锁(record locks),如果看过之前写的行锁的文章那么对这个锁应该会很了解,见名知意记录锁就是对某条数据进行加锁,比如对一条数据加共享锁:select * from test_index lock in share mode;,对一条数据加独占锁:select * from test_index for update;

且共享锁和独占锁满足以下规则,如下图:

image.png 对应的情况不再做演示,之前的文章有。

2.间隙锁

间隙锁(gap locks),间隙可以理解为区域,那么间隙锁也就是锁定多条记录的行锁,(温馨提示,间隙锁貌似只有MySQL8.0版本才有或者说使用,因为我在阿里云服务器MySQL5.7版本上无法演示出这种效果,当时心态很裂开!)

举个例子,还是表test_index,查看下当前表的记录,如下图:

image.png

如果我执行如下SQL:select * from test_index where id = 8 for update;因为id等于8的这条记录是根本不存在的,所以锁肯定不会是行锁独占锁,但是也不是不加锁,此时加锁的类型就是间隙锁,范围就是在id等于8的上一条记录和下一条记录的区间也就是6到11(> 6 && < 11),如果此时我新开事务二去想表新增一条记录id为7的,那么事务二会变成阻塞状态,造成这种情况的原因就是因为innodb引擎给6到11的记录加上了间隙锁,下面看操作。

事务一执行上述SQL且事务不提交:

image.png

新开事务二,执行SQL:INSERT INTO testdb.test_index(id, name, create_date, desc, unique_num, test_add) VALUES (7, '7', '2022-04-04', '7~', 7, NULL);

image.png

事务二最终:

image.png

gap锁的仅仅是为了防止插入幻影记录而提出的,试想一下如果我某个事务查询id区间为6到100的数据,第一次查询只有两条数据id为6、7,此时事务二新增一条id为8的记录且提交事务,这时事务一再次查询id区间为6到100的数据发现数据多了一条,事务一很懵逼啊,我都还没提交事务呢,咋数据还多了,这其实也就是幻读的情况,多出来的数据就是幻影记录。

3.临键锁

临键锁(next key locks),实际上是记录索和间隙锁的结合版,记录锁是针对某条记录,而间隙锁是某个区间且是不包括头尾的,如果此时我们需要锁定区间又需要锁定这个区间边界的记录那就需要临键锁。

直接看例子,新开事务一执行SQL:select * from test_index where id > 6 and id <=11 for update;

image.png

新开事务二执行SQL:select * from test_index where id = 11 lock in share mode

image.png

根据上述情况可以发现事务二被阻塞了,这就是记录锁,下面事务二新增id为7的记录,执行SQL:INSERT INTO testdb.test_index(id, name, create_date, desc, unique_num, test_add) VALUES (7, '7', '2022-04-04', '7~', 7, NULL);

image.png

可以发现事务二又被阻塞了,这种情况就是间隙锁,结合起来就是临键锁。