• MYSQL锁机制 - 锁的简述 | 索引对行级锁的影响


    说明:本栗子所用为mysql 8.0 + ; 隔离级别为默认的RR级别

    0. 锁的分类:

    按锁的粒度来分,有表锁、行级锁、页锁;这里主要讲行级锁

    按兼容性来分,有排它锁和共享锁:

    • 排它锁:又叫X锁和写锁;事务对资源加了排他锁,其他事务就不能再给它加任何锁了
    • 共享锁:又叫S锁和写锁;事务对资源加了共享锁,其他事务不能加排它锁,但能加共享锁
      ·

    手动加锁:

    • 手动加共享锁:SELECT … LOCK IN SHARE MODE
    • 手动加排它锁:SELECT … FOR UPDATE
      ·

    当前读与快照读:

    • 快照读:就是普通的select语句,快照读是不会对数据上锁的
    • 当前读:读取的是最新版本数据, 并且对读取的记录加排他锁;像update , delete , insert,lock in share mode,for update语句

    InnoDB默认是支持行级锁的,包括以下几种模式:

    • 记录锁(Record Lock):对索引项加锁,锁定符合条件的行
    • 间隙锁(Gap Lock):对索引项之间的“间隙”加锁,锁定记录的范围(开区间)
    • 临键锁(Next-key Lock):锁定索引项本身和索引范围(左开右闭),结合了记录锁和间隙锁;
    • 意向锁(Intention Lock):是一种表级锁,但不与行级锁冲突;

    InnoDB存储引擎中默认使用的是Next-Key Lock,但在一些场景下会退化成记录锁或间隙锁

    1. 主键/唯一索引对行级锁的影响:

    • 本栗子实验,起始数据都为0,5,10,15,20;每次实现完恢复数据,再进行实验;
    • 此范围内临建锁有(-∞,0] ,(0,5] ,(5,10],(10,15],(15,20],(20,+∞]
    1.1. 唯一索引等值条件匹配场景:
    • 对于当前读,当条件数据存在时,「临建锁 」会退化成「记录锁」
    • 对于当前读,当条件数据不存在时,「临建锁 」会退化成「间隙锁」

    【条件数据存在】:

    • 对id=5的行更新,加上了X锁,别的事务不可以对该行操作,但可以对其他行操作(更新id=10的数据)
      ·在这里插入图片描述
      `

    【条件数据不存在】:

    • 对id=8的行加X锁,原本是间隙锁(5,10 ] ,由于没有记录,退化成间隙锁(5,10);别的事务不能对该间隙进行写操作,故插入id=6阻塞:
      ·
      在这里插入图片描述
    1.2. 唯一索引条件范围匹配场景:
    • 对于当前读,锁的范围是条件范围所在的「临建锁」并集,起始范围可能会退化成记录锁,并止于往后第一个不匹配范围的数据所在临建锁
    • 我实验的结果和别人的不太一样,别人的是止于间隙锁
    • 比如>3 and id <15,条件范围的临建锁有(0,5] ,(5,10],(10,15],所以最终锁的范围是(0,15]
      ·在这里插入图片描述
    • 如果是>=5 and id <=15,条件范围的临建锁有5 ,(5,10],(10,15],(15,20],所以最终锁的范围是[5,20]
    • id=5的数据满足条件,临建锁退化成记录锁5;id=15的数据满足条件,所以要往后查找到不满足的记录20才停止加锁
      ·在这里插入图片描述

    2. 非唯一索引对行级锁的影响:

    对age字段加上普通索引

    2.1. 非唯一索引等值条件匹配场景:
    • 对于当前读,当条件数据存在时,除了加条件所在的「临建锁」还会加上往后第一个不匹条件的数据所在「间隙锁」
    • 对于当前读,当条件数据不存在时,条件所在的「临建锁 」会退化成「间隙锁」

    【条件数据存在】:

    • 对age=15的行更新,加上了(10,15]的临建锁,往后第一个不匹配的数据是age=20,所以还会加上(15,20)间隙锁,所以锁的范围是(10,20)
      ·在这里插入图片描述
      【条件数据不存在】:
    • 对age=13的行更新,加上了(10,15]的临建锁,但条件数据不存在,所以退化成(10,15)间隙锁
      ·在这里插入图片描述
    2.2. 非唯一索引条件范围匹配场景:
    • 对于当前读,锁的范围是条件范围所在的「临建锁」并集,起始范围可能不会退化成记录锁,并止于往后第一个不匹配范围的数据所在临建锁
    • 比如age>8 and age <20,条件范围的临建锁有(5,10] ,(10,15],(15,20],所以最终锁的范围是(5,20]
      ·在这里插入图片描述·
    • 比如age>=10 and age <=20,条件范围的临建锁有(5,10] ,(10,15],(15,20],(20,25]所以最终锁的范围是(5,20]
    • id=10的数据满足条件,普通索引临建锁不会退化成记录锁;id=20的数据满足条件,所以要往后查找到不满足的记录25才停止加锁
      ·在这里插入图片描述

    3. 条件没有索引对行级锁的影响:

    • 对于当前读,条件没有索引,会导致行级锁升级为表锁

    name字段是没有索引的,不管数据存不存在,行级锁会升级为表锁
    ·在这里插入图片描述

    4. 小结:

    【对于当前读,等值匹配条件数据存在时】

    • 唯一索引会将「临建锁 」会退化成「记录锁」
    • 非唯一索引「临建锁 」不会退化,并且还会加上往后第一个不匹条件的数据所在「间隙锁」
      ·

    【对于当前读,等值匹配条件数据不存在时】

    • 唯一索引和非唯一索引「临建锁 」都会退化成「间隙锁」
      ·

    【对于当前读,条件范围匹配】

    • 锁的范围是条件范围所在的「临建锁」并集,并止于往后第一个不匹配范围的数据所在临建锁
    • 唯一索引的起始范围可能会退化成记录锁,非唯一索引的起始范围不会退化成记录锁
      ·

    【对于当前读,条件字段没有索引对行级锁的影响】

    • 会导致行级锁升级为表锁,使用时尤为注意

    以上是基于mysql 8.0 + ,默认RR级别,索引对行级锁影响得实验结论,如有错误,欢迎指正

  • 相关阅读:
    Maven系列第5篇:私服详解
    【案例分享】BenchmarkSQL 5.0 压测 openGauss 5.0.0
    【JavaWeb】火车票管理系统 (三)用户删除之在jsp页面上显示数据
    工业环网交换机运行原理
    防止Android点击app图标应用重启
    等级保护测评需要多长时间 ?
    使用 OpenCV 测量物体尺寸
    在 Vue.js 中,使用 watch 监听data变量如:对象属性/data变量
    juc详解
    如何使用vuex
  • 原文地址:https://blog.csdn.net/weixin_43901882/article/details/126335771