MySQL行级锁-详解!

什么时候加行级锁

 //对读取的记录加共享锁(S型锁)
 select ... lock in share mode;
 ​
 //对读取的记录加独占锁(X型锁)
 select ... for update;

当事务提交了,锁就会被释放

 //对操作的记录加独占锁(X型锁)
 update table .... where id = 1;
 ​
 //对操作的记录加独占锁(X型锁)
 delete from table where id = 1;

共享锁(S锁)满足读读共享,读写互斥。独占锁(X锁)满足写写互斥、读写互斥。 【指行(记录)锁】间隙锁之间是兼容的(因为目的是为了防止幻读)

行级锁类型

在读已提交隔离RC级别下,行级锁的种类只有记录锁,也就是仅仅把一条记录锁上。

在可重复读隔离RR级别下,行级锁的种类除了有记录锁,还有间隙锁(目的是为了避免幻读),所以行级锁的种类主要有三类:

  • Record Lock,记录锁,也就是仅仅把一条记录锁上;

  • Gap Lock,间隙锁,锁定一个范围,但是不包含记录本身;

  • Next-Key Lock:Record Lock + Gap Lock 的组合,锁定一个范围,并且锁定记录本身。

MySQL 是怎么加行级锁的?

加锁的对象是索引,加锁的基本单位是 next-key lock,它是由记录锁和间隙锁组合而成的,next-key lock 是前开后闭区间,而间隙锁是前开后开区间。【锁是加在索引上的】

在能使用记录锁或者间隙锁就能避免幻读现象的场景下, next-key lock 就会退化成记录锁或间隙锁

select * from performance_schema.data_locks\G;查看事务执行 SQL 过程中加了什么锁。

LOCK_TYPE 中的 RECORD 表示行级锁,而不是记录锁的意思。

通过 LOCK_MODE 可以确认是 next-key 锁,还是间隙锁,还是记录锁:

  • 如果 LOCK_MODE 为 X,说明是 next-key 锁;

  • 如果 LOCK_MODE 为 X, REC_NOT_GAP,说明是记录锁;

  • 如果 LOCK_MODE 为 X, GAP,说明是间隙锁;

  • LOCK_DATA 就表示锁的范围「右边界」

总的思路就是,尽可能避免幻读的发生(不让其他记录的插入),对于等值查询(>=)查到的加临建锁或者记录锁(看是范围查询 [大于情况才记录锁] 还是等值查询),因为这个记录等值记录也要上锁。对于非等值的查到了,只是加间隙锁,因为是开区间的。

注意:结合临建锁(包含记录锁)是左开右闭(在>=时是记录锁锁住左边界)。 间隙锁是开区间。

注意:

  • 对于不唯一的不加记录锁的原因【因为不具有唯一性,所以如果只加记录锁(记录锁无法防止插入,只能防止删除或者修改)】

  • 因为【插入时不会阻塞,报主键冲突错误,删除和更新则会阻塞】

在线上在执行 update、delete、select ... for update 等具有加锁性质的语句,一定要检查语句是否走了索引,如果是全表扫描的话,会对每一个索引加 next-key 锁,相当于把整个表锁住了,这是挺严重的问题。

唯一索引(主键索引)等值查询

索引上的等值查询(唯一索引时),给不存在的记录加锁时,优化为间隙锁

此处「唯一索引」是用「主键索引」作为案例说明的

加锁的对象是针对索引,因为这里查询语句扫描的 B+ 树是聚簇索引树,即主键索引树,所以是对主键索引加锁。将对应记录的主键索引加 记录锁后,就意味着其他事务无法对该记录进行更新和删除操作了。

唯一索引进行等值查询的时候,查询的记录存不存在,加锁的规则也会不同:

  • 当查询的记录是「存在」的,在索引树上定位到这一条记录后,将该记录的索引中的 next-key lock 会退化成「记录锁」。【因为仅靠记录锁也能避免幻读的问题。】

  • 当查询的记录是「不存在」的,在索引树找到第一条大于该查询记录的记录后,将该记录的索引中的 next-key lock 会退化成「间隙锁」【需要锁住这个不存在的id防止被别人插入了,不需要锁住比他的大的这一条数据】开区间(因为第一条大于的是已经存在的,所以会报主键冲突的错,不需要加) 【退化原因:对于大于所查的id,并不需要保证他的幻读问题,只要保证所查询的id不要出现幻读问题就可以】

二级索引:都会对查到的记录的主键索引项加上记录锁,还会对二级索引加行级锁(唯一索引的话,退化规则和主键索引一样)

不存在的锁边界:LOCK_DATA 就表示锁的范围「右边界」(此处为5),锁范围的「左边界」是表中 id 为 5 的上一条记录的 id 值,即 1。

唯一索引范围查询

索引上的范围查询(唯一索引)--会访问到不满足条件的第一个值为止

临建锁都是两个已有的记录之间的锁 (a,b] 。

当唯一索引进行范围查询时,会对每一个扫描到的索引加 next-key 锁,然后如果遇到下面这些情况,会退化成记录锁或者间隙锁

  • 情况一:针对「大于等于」的范围查询,因为存在等值查询的条件,那么如果等值查询的记录是存在于表中,那么该记录的索引中的 next-key 锁会退化成记录锁。【其他的大于呢???就不会退化为间隙锁了,直接next-key-lock】------【 Innodb 存储引擎中,会用一个特殊的记录来标识最后一条记录,该特殊的记录的名字叫 supremum pseudo-record ,所以后面的next-key是(,+oo]】----【等于时的等值条件为什么只有她是记录锁,因为临建锁是左开右闭,会导致左边界的等值查询无法锁住,所以就用记录锁】

  • 情况二:针对「小于或者小于等于」的范围查询,要看条件值的记录是否存在于表中:

    • 当条件值的记录在表中(存在),如果是「小于」条件的范围查询,扫描到终止范围查询的记录时,该记录的索引的 next-key 锁会退化成间隙锁,其他扫描到的记录,都是在这些记录的索引上加 next-key 锁;如果「小于等于」条件的范围查询,扫描到终止范围查询的记录时,该记录的索引 next-key 锁不会退化成间隙锁。其他扫描到的记录,都是在这些记录的索引上加 next-key 锁。【把要查的都锁住,其他的不影响,所以要临建锁】-----【此处等值的加记录锁大可不必,因为又不止锁这个记录, 大于情况是因为临建锁左开右闭

    • 当条件值的记录不在表(不存在)中,那么不管是「小于」还是「小于等于」条件的范围查询,扫描到终止范围查询的记录时,该记录的索引的 next-key 锁会退化成间隙锁,其他扫描到的记录,都是在这些记录的索引上加 next-key 锁。【因为不存在这个终止条件,不需要锁住她】

非唯一索引等值查询

索引上的等值查询(普通索引),向右遍历时最后一个【因为可能不唯一】值不满足查询需求时,next-key lock 退化为间隙锁

查询记录的存不存在:区别在于会不会对主键索引添加记录锁(他是唯一性的)

因为存在两个索引,一个是主键索引,一个是非唯一索引(二级索引),所以在加锁时,同时会对这两个索引都加锁,但是对主键索引加锁的时候,只有满足查询条件的记录才会对它们的主键索引加锁。

  • 当查询的记录「存在」时,由于不是唯一索引,所以肯定存在索引值相同的记录,于是非唯一索引等值查询的过程是一个扫描的过程,直到扫描到第一个不符合条件的二级索引记录就停止扫描,然后在扫描的过程中,对扫描到的二级索引记录加的是 next-key 锁,而对于第一个不符合条件的二级索引记录,该二级索引的 next-key 锁会退化成间隙锁【因为不具有唯一性,所以如果只加记录锁(记录锁无法防止插入,只能防止删除或者修改)】。同时,在符合查询条件的记录的主键索引上加记录锁。【因为只有一条记录,唯一性】

  • 当查询的记录「不存在」时,扫描到第一条不符合条件的二级索引记录,该二级索引的 next-key 锁会退化成间隙锁。因为不存在满足查询条件的记录,所以不会对主键索引加锁。【因为她不存在呀】

非唯一索引范围查询

非唯一索引范围查询,索引的 next-key lock 不会有退化为间隙锁和记录锁的情况,也就是非唯一索引进行范围查询时,对二级索引记录加锁都是加 next-key 锁。

没有加索引的语句

对于有加索引的,是查询记录的时候,是通过索引扫描的方式查询的,然后对扫描出来的记录进行加锁。

对于没有加索引的在查询的时候就会对每一条记录的索引上都会加 next-key 锁,这样就相当于锁住的全表,这时如果其他事务对该表进行增、删、改操作的时候,都会被阻塞。

update 和 delete 语句如果查询条件不加索引,那么由于扫描的方式是全表扫描。【不只是select、语句】

总结:

唯一索引等值查询:

  • 当查询的记录是「存在」的,在索引树上定位到这一条记录后,将该记录的索引中的 next-key lock 会退化成「记录锁」

  • 当查询的记录是「不存在」的,在索引树找到第一条大于该查询记录的记录后,将该记录的索引中的 next-key lock 会退化成「间隙锁」

非唯一索引等值查询:

  • 当查询的记录「存在」时,由于不是唯一索引,所以肯定存在索引值相同的记录,于是非唯一索引等值查询的过程是一个扫描的过程,直到扫描到第一个不符合条件的二级索引记录就停止扫描,然后在扫描的过程中,对扫描到的二级索引记录加的是 next-key 锁,而对于第一个不符合条件的二级索引记录,该二级索引的 next-key 锁会退化成间隙锁。同时,在符合查询条件的记录的主键索引上加记录锁

  • 当查询的记录「不存在」时,扫描到第一条不符合条件的二级索引记录,该二级索引的 next-key 锁会退化成间隙锁。因为不存在满足查询条件的记录,所以不会对主键索引加锁

非唯一索引和主键索引的范围查询的加锁规则不同之处在于:

  • 唯一索引在满足一些条件的时候,索引的 next-key lock 退化为间隙锁或者记录锁。

  • 非唯一索引范围查询,索引的 next-key lock 不会退化为间隙锁和记录锁。

唯一索引:

 

 

非唯一索引(二级索引)

对于二级索引中唯一索引规格和主键索引一样!(会用到记录锁,因为唯一)

  • 17
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值