用动态的观点看加锁

前言

间隙锁的两原则两优化一bug

原则1:加锁的基础是加next-lock 即间隙锁

原则2:查找过程中访问到的对象都会加锁

优化1:等值查询中,如果是主键索引上的查找,会退化成行锁

优化2:等值查询中,向右遍历时,如果最后一个值不符合,则会退化成间隙锁

一bug:唯一主键的返回查询,必须找到第一个不满足的才会停止


用动态的观点看加锁

间隙锁的两原则两优化一bug

原则1:加锁的基础是加next-lock 即间隙锁

原则2:查找过程中访问到的对象都会加锁

优化1:等值查询中,如果是主键索引上的查找,会退化成行锁

优化2:等值查询中,向右遍历时,如果最后一个值不符合,则会退化成间隙锁

一bug:唯一主键的返回查询,必须找到第一个不满足的才会停止

间隙锁的加锁范围

间隙锁的加锁范围是基于查询条件和起始位置以及锁的方向

其中锁的方向可以这样理解,由于在范围查询(1,5)时,查询到5之后,并不知道5之后是不是下一条数据还是5,所以会继续往后扫描一下扫描到7,那么认为范围已经确定。

但是根据原则2,查找过程中访问到的对象都会加锁,所以5和7之间的间隙也会被加上间隙锁。但是0和1之间不会。

示例

假设表中有以下数据:

id value
1 A
3 B
5 C
7 D

如果一个事务发起了一个 SELECT FOR UPDATE 查询,查询条件为 id BETWEEN 1 AND 5,那么 InnoDB 会加锁以下区域:

  • 锁定 id = 1id = 3 行之间的间隙(即 id = 2 的位置)。
  • 锁定 id = 3id = 5 行之间的间隙(即 id = 4 的位置)。
  • 并不会锁定 id = 5 行本身 ,而是锁定了 id = 5id = 7 之间的间隙。

我们说加锁单位是next-key lock,都是前开后闭区间,如:(0,5]、(5,10]和(10, 15)

哪些查询条件是等值查询,但看起来像范围查询呢?

由于上面提到的等值查询,其实并不仅仅是=的查询还有一些隐式的查询。

IN 查询(等值集合查询)
  • 查询条件WHERE id IN (1, 2, 3, 4)
  • 解释 :虽然 IN 语句中的条件看起来像是多个等值条件,但实际上它会被 拆解为多个等值查询 ,每个等值条件会分别查找一个数据行。这会导致数据库为每个条件锁住一行,最终结果就是 多个行锁。但是,这个查询的锁行为实际上是多次等值查询的合成,锁住了多行,而不是范围查询。
  • 特别注意 :虽然 IN 是等值查询的组合,但它的锁机制跟单个等值查询类似,只不过是对多个行进行锁定。
2. BETWEEN 查询(等值查询范围)
  • 查询条件WHERE id BETWEEN 1 AND 10
  • 解释 :虽然 BETWEEN 通常被视为范围查询,但在某些情况下,数据库可以通过索引优化 将其转换为等值查询的多个条件。例如,数据库可能将 BETWEEN 1 AND 10 拆解为多个等值查询,如:id = 1 OR id = 2 OR id = 3 ...,然后用 行锁 锁住每个匹配的行。
  • 特别注意 :这里并没有使用间隙锁,只要查询的范围没有数据被插入的空隙,查询会退化为对每个行的锁定。
3. =(等值)条件与 >=<= 结合的查询
  • 查询条件WHERE id >= 5 AND id <= 10
  • 解释 :尽管这是一个范围查询,InnoDB 会尝试使用索引进行优化,如果有适合的索引(例如 id 索引),它可以把这种查询当作"等值查询的范围"进行处理。由于它是有索引支持的,可以对符合条件的行进行锁定。
  • 特别注意 :虽然查询是一个范围查询,但如果查询使用的是主键或者唯一索引,并且符合等值条件的行比较少,数据库可能退化为行锁 的情况。也就是说,WHERE id >= 5 AND id <= 10 在某些情况下不会使用间隙锁,而是退化为对所有符合条件的行加行锁。
4. 某些类型的多列等值查询
  • 查询条件WHERE (col1 = 'A' AND col2 = 'B')
  • 解释 :如果 (col1, col2) 是联合索引或主键索引,数据库可以使用复合索引进行查询。在这种情况下,查询实际上是等值查询,只不过是针对多个列的联合索引。即使是复合索引,这种查询也会按照每个匹配条件的行锁来处理。
  • 特别注意:此类查询在某些情况下会用行锁替代间隙锁,尤其是当查询范围比较明确时。
5. 前缀索引查询
  • 查询条件WHERE name LIKE 'A%'
  • 解释 :如果 name 列上有一个前缀索引,LIKE 'A%' 查询可能会退化为一个范围查询。虽然 LIKE 查询通常是范围查询,但在前缀索引的情况下,它可以被优化为对特定范围的等值查询,并加锁这些行。
  • 特别注意:这种情况涉及到索引优化,如果数据库能使用索引高效地找到匹配项,则会退化为加行锁。否则,可能会使用间隙锁。

死锁回滚

对于死锁,mysql会根据回滚那个事务代价更小,而回滚那个。

相关推荐
Jay Kay1 小时前
跳跃表可视化深度解析:动态演示数据结构核心原理
数据结构·数据库
千册4 小时前
python+pyside6+sqlite 数据库测试
数据库·python·sqlite
fouryears_234174 小时前
适配器模式——以springboot为例
java·spring boot·适配器模式
汽车功能安全啊5 小时前
利用对称算法及非对称算法实现安全启动
java·开发语言·安全
paopaokaka_luck5 小时前
基于Spring Boot+Vue的吉他社团系统设计和实现(协同过滤算法)
java·vue.js·spring boot·后端·spring
java叶新东老师5 小时前
PowerDesigner 画ER图并生成sql 教程
数据库·sql
Jonariguez6 小时前
Mysql InnoDB存储引擎
数据库·mysql
nbsaas-boot7 小时前
SQL Server 窗口函数全指南(函数用法与场景)
开发语言·数据库·python·sql·sql server
Y.ppm7 小时前
数分思维12:SQL技巧与分析方法
数据库·sql
森叶7 小时前
Claude Code 安装向量数据库MCP服务
数据库