暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL数据库锁:Record Lock, Gap Lock 和 Next-Key Lock

猿java 2024-06-09
227

你好,我是猿java。

点击关注公众号👇,Java干货时送,面试简历免费指导!


InnoDB引擎 在 共享锁和排他锁 文章中,我们详细分析了共享锁和排他锁在MySQL
中是如何工作的,今天,我们接着分析InnoDB
引擎的 3种行锁。

MySQL
InnoDB
引擎的行锁主要有三类:

  1. Record Lock
    :记录锁,是在索引记录上加锁;
  2. Gap Lock
    :间隙锁,锁定一个范围,但不包含记录;
  3. Next-key Lock
    Next-key Lock = Gap Lock + Record Lock
    ,它锁定了一个范围(Gap Lock实现),并且锁定记录本身(Record Lock实现);

Record Lock

什么是 Record Lock?

Record Lock
,记录锁,它是针对索引记录的锁,锁定的总是索引记录。在多用户数据库系统中,多个事务可能会同时尝试读取或修改同一条记录,Record Lock
确保只有一个事务能在某一时刻修改该记录,其他事务只能读取,或者在写锁释放后再进行修改。

举例说明

为了更好的说明Record Lock
,我们以下面的顺序执行流来进行验证:

加锁线程  sessionA线程B  sessionB线程B  sessionC
#开启事务
begin;


给user表id=1加写锁
select id from user
where id = 1 for update;



update user set
name='name121'
where id = 1;



查看InnoDB
监视器中记录锁数据
show engine innodb status\G
commit提交事务
record lock 被释放



被堵塞的update操作执行ok

示例执行结果如下图:

通过上面的示例可以看出:

  • 事务A(sessionA)对id=1
    加排他锁之后产生了记录锁
  • 事务B(sessionB)对id=1
    update
    操作被阻塞了
  • 事务C(sessionC)可以查看到Record Lock

Gap Lock

什么是Gap Lock?

Gap Lock
,间隙锁,它是一种行级锁,锁住两个索引记录之间的间隙
,而不是实际的数据记录,由InnoDB
隐式添加。

如下图:(1,3) 表示锁住记录1 和记录3 之间的间隙,这样记录2 就无法插入,间隙可能跨越单个索引值、多个索引值,甚至是空。

img.png

InnoDB
中,间隙锁是通过索引来实现的。这意味着间隙锁只能作用于索引,而不能直接作用于非索引列。当一个事务对某个索引列上的间隙加锁时,其他事务就无法在这个间隙中插入新的记录。

举例说明

为了更好的说明Gap Lock
间隙锁,我们以下面的顺序执行流来进行验证:

加锁线程  sessionA线程B  sessionB线程C  sessionC
#开启事务
begin;


加锁
select * from user
where age = 10 for share;



insert into user(id,age) values(2,20);


#查看InnoDB
监视器中记录锁数据
show engine innodb status\G
commit提交事务
Gap Lock被释放



# 被堵塞的insert
操作执行成功

示例执行结果如下图:

通过上面的示例执行结果可以看出:

  • 事务A(sessionA)在加共享锁的时候产生了间隙锁(Gap Lock)
  • 事务B(sessionB)对间隙中进行insert/update
    操作,需要先获取排他锁(X),导致阻塞
  • 事务C(sessionC)通过show engine innodb status\G
    指令可以查看到间隙锁的存在。

需要说明,间隙锁只是锁住间隙内部的范围,在间隙外的insert/update
操作不会受影响。

Next-Key Lock

什么是Next-Key Lock?

Next-Key Lock
,称为临键锁,它是Record Lock + Gap Lock
的组合,用来锁定一个范围,并且锁定记录本身锁,它是一种左开右闭的范围,可以用符号表示为:(a,b]。如下图:

img.png

举例说明

为了更好的说明Next-Key Lock
,我们以下面的顺序执行流来进行验证:

加锁线程  sessionA线程B  sessionB线程C  sessionC线程D  sessionD
#开启事务
begin;



#加锁
select * from user
where age = 10 for share;




#获取锁失败
insert操作被堵塞
insert into
user(id,age)
values(2,20);




#update被堵塞
update user
set name='name1'
where age = 10;
#查看InnoDB
监视器中记录锁数据
show engine innodb status\G
提交事务Gap Lock被释放  
commit




被堵塞的insert操作执行ok#被堵塞的update操作执行成功

示例执行结果如下图:

通过上面的示例执行结果可以看出:

  • 事务A(sessionA)在加共享锁的时候产生了间隙锁(Gap Lock)
  • 事务B(sessionB)对间隙中进行insert
    操作,需要先获取排他锁(X),导致阻塞。
  • 事务C(sessionC)对间隙中进行update
    操作,需要先获取排他锁(X),导致阻塞。
  • 事务D(sessionD)通过show engine innodb status\G
    指令可以查看到间隙锁的存在。需要说明的,间隙锁只是锁住间隙内部的范围,在间隙外的insert/update
    操作不会受影响。

总结

Record Lock
Gap Lock
Gap Lock
3种锁是存在MySQL
InnoDB
引擎的行锁,MyISAM引擎没有:

  1. Record Lock
    :记录锁,是在索引记录上加锁;
  2. Gap Lock
    :间隙锁,锁定一个范围,但不包含记录,即(A,B)
  3. Next-key Lock
    Next-key Lock = Gap Lock + Record Lock
    ,它锁定了一个范围(Gap Lock实现),并且锁定记录本身(Record Lock实现),即(A,B]
    ;;

这 3种锁都是InnoDB
引擎隐式添加的,目的是为了解决可重复读隔离级别下幻读的现象。

学习交流

文章总结不易,看到这里的小伙伴,感谢帮忙点赞,在读,或者转发给更多的好友,我们将为你呈现更多的干货, 欢迎关注公众号:猿 java

PS:因公众号平台更改了推送规则,如果不想错过内容,记得读完点一下“在看”,加个“星标”。

文章转载自猿java,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论