把MySQL中的各种锁及其原理都画出来( 六 )


把MySQL中的各种锁及其原理都画出来

文章插图
 
聚簇索引 , 范围查询上面介绍的场景都是 where 从句的等值查询 , 而范围查询的加锁又是怎么样的呢?我们慢慢来看 。
下图是 UPDATE book SET score = 9.2 WHERE ID <= 25 在 RC 和 RR 隔离等级下的加锁情况 。
RC 场景下与等值查询类似 , 只会在涉及的 ID = 10 , ID = 18 和 ID = 25 索引上加排他记录锁 。
把MySQL中的各种锁及其原理都画出来

文章插图
 
而在 RR 隔离等级下则有所不同 , 它会加上间隙锁 , 和对应的记录锁合并称为 Next-Key 锁 。除此之外 , 它还会在(25, 30] 上分别加 Next-Key 锁 。这一点是十分特殊的 , 具体原因还需要再探究 。
二级索引 , 范围查询下图展示了 UPDATE book SET ISBN = N0001 WHERE score <= 7.9 在 RR 级别下的加锁情况 。
把MySQL中的各种锁及其原理都画出来

文章插图
 
修改索引值UPDATE 语句修改索引值的情况可以分开分析 , 首先 Where 从句的加锁分析如上文所述 , 多了一步 Set 部分的加锁 。
下图展示了 UPDATE book SET Author = 'John' WHERE ID = 10 在 RC 和 RR 隔离等级下的加锁情况 。除了在主键 ID 上进行加锁 , 还会对二级索引上的 Bob(就值) 和 John(新值) 上进行加锁 。
把MySQL中的各种锁及其原理都画出来

文章插图
 
DELETE 语句加锁分析一般来说 , DELETE 的加锁和 SELECT FOR UPDATE 或 UPDATE 并没有太大的差异 。
因为 , 在 MySQL 数据库中 , 执行 DELETE 语句其实并没有直接删除记录 , 而是在记录上打上一个删除标记 , 然后通过后台的一个叫做 purge 的线程来清理 。从这一点来看 , DELETE 和 UPDATE 确实是非常相像 。事实上 , DELETE 和 UPDATE 的加锁也几乎是一样的 。
INSERT 语句加锁分析接下来 , 我们来看一下 Insert 语句的加锁情况 。
Insert 语句在两种情况下会加锁:
  • 为了防止幻读 , 如果记录之间加有间隙锁 , 此时不能 Insert;
  • 如果 Insert 的记录和已有记录造成唯一键冲突 , 此时不能 Insert;
除了上述情况 , Insert 语句的锁都是隐式锁 。隐式锁是 InnoDB 实现的一种延迟加锁的机制来减少加锁的数量 。
隐式锁的特点是只有在可能发生冲突时才加锁 , 减少了锁的数量 。另外 , 隐式锁是针对被修改的 B+Tree 记录 , 因此都是记录类型的锁 , 不可能是间隙锁或 Next-Key 类型 。
具体 Insert 语句的加锁流程如下:
  • 首先对插入的间隙加插入意向锁(Insert Intension Locks)如果该间隙已被加上了间隙锁或 Next-Key 锁 , 则加锁失败进入等待;如果没有 , 则加锁成功 , 表示可以插入;
  • 然后判断插入记录是否有唯一键 , 如果有 , 则进行唯一性约束检查如果不存在相同键值 , 则完成插入如果存在相同键值 , 则判断该键值是否加锁如果没有锁 ,  判断该记录是否被标记为删除如果标记为删除 , 说明事务已经提交 , 还没来得及 purge , 这时加 S 锁等待;如果没有标记删除 , 则报 duplicate key 错误;如果有锁 , 说明该记录正在处理(新增、删除或更新) , 且事务还未提交 , 加 S 锁等待;
  • 插入记录并对记录加 X 记录锁;
后记本文中讲解的 SQL 语句都是十分简单的 , 当 SQL 语句包含多个查询条件时 , 加锁的分析过程就往往更加复杂 。我们需要使用 MySQL 相关的工具进行分析 , 并且有时甚至需要查询 MySQL 相关的日志信息来了解到底语句加了什么锁或者为什么产生死锁 , 下篇文章中我们就主要了解一下这些内容 , 请大家持续关注 。




推荐阅读