MySQL-锁-间隙锁案例篇

本文详细分析了MySQL中间隙锁(Gap Locks)和临键锁(Next-Key Locks)的工作原理,通过多个实战案例,包括等值查询、范围查询和更新操作等,展示了不同情况下锁的使用和影响。内容涵盖了如何查看死锁、锁等待以及如何避免死锁,强调了锁在索引上的应用和管理,对于理解和优化MySQL事务处理具有重要指导意义。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

间隙加锁规则

  1. 原则1:加锁的基本单位是next-key lock。希望你还记得,next-key lock是前开后闭区间。
  2. 原则2:查找过程中访问到的对象才会加锁。
  3. 优化1:索引上的等值查询,给唯一索引加锁的时候,next-key lock退化为行锁。
  4. 优化2:索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock退化为间隙锁。
  5. 一个bug:唯一索引上的范围查询会访问到不满足条件的第一个值为止。

注意!有行才会加行锁。如果查询条件没有命中行,那就加next-key lock。当然,等值判断的时候,需要加上优化2

(即:索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock退化为间隙锁。)

<=到底是间隙锁还是行锁?其实,这个问题,你要跟“执行过程”配合起来分析。
在InnoDB要去找“第一个值”的时候,是按照等值去找的,用的是等值判断的规则;
找到第一个值以后,要在索引内找“下一个值”,对应于我们规则中说的范围查找。

案例SQL

所有案例都是在可重复读隔离级别(repeatable-read)下验证的

CREATE TABLE `t` (
  `id` int(11) NOT NULL,
  `c` int(11) DEFAULT NULL,
  `d` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `c` (`c`)
) ENGINE=InnoDB;

insert into t values(0,0,0),(5,5,5),
(10,10,10),(15,15,15),(20,20,20),(25,25,25);

案例1-等值查询间隙锁

由于表t中没有id=7的记录,所以用我们上面提到的加锁规则判断一下的话:

  1. 根据原则1,加锁单位是next-key lock,session A加锁范围就是(5,10];
  2. 同时根据优化2,这是一个等值查询(id=7),而id=10不满足查询条件,next-key lock退化成间隙锁,因此最终加锁的范围是(5,10)。

所以,session B要往这个间隙里面插入id=8的记录会被锁住,但是session C修改id=10这行是可以的。

案例2-非唯一索引等值锁

这里session A要给索引c上c=5的这一行加上读锁。

  1. 根据原则1,加锁单位是next-key lock,因此会给(0,5]加上next-key lock。
  2. 要注意c是普通索引,因此仅访问c=5这一条记录是不能马上停下来的,需要向右遍历,查到c=10才放弃。根据原则2,访问到的都要加锁,因此要给(5,10]加next-key lock。
  3. 但是同时这个符合优化2:等值判断,向右遍历,最后一个值不满足c=5这个等值条件,因此退化成间隙锁(5,10)。
  4. 根据原则2 ,只有访问到的对象才会加锁,这个查询使用覆盖索引,并不需要访问主键索引,所以主键索引上没有加任何锁,这就是为什么session B的update语句可以执行完成。

但session C要插入一个(7,7,7)的记录,就会被session A的间隙锁(5,10)锁住。

在这个例子中,lock in share mode只锁覆盖索引,但是如果是for update就不一样了。 执行 for update时,系统会认为你接下来要更新数据,因此会顺便给主键索引上满足条件的行加上行锁

这个例子说明,锁是加在索引上的; 同时,它给我们的指导是,如果你要用lock in share mode来给行加读锁避免数据被更新的话,就必须得绕过覆盖索引的优化,在查询字段中加入索引中不存在的字段。

所以,如果一个select * from … for update 语句,优化器决定使用全表扫描,那么就会把主键索引上next-key lock全加上。

案例3:主键索引范围锁

mysql> select * from t where id=10 for update;
mysq
### MySQL 间隙锁(Gap Lock)原理及应用场景 #### 一、间隙锁的定义与作用 间隙锁是一种用于防止其他事务在指定范围内插入新记录的机制。它主要应用于 InnoDB 存储引擎,在涉及范围查询时会自动启用。当使用范围条件而非精确匹配来访问数据时,InnoDB 不仅会对已存在的记录,还会对这些记录之间的“间隙”施定[^1]。 这种设计的主要目的是为了阻止并发事务向某个特定范围插入新的记录,从而有效避免幻读现象的发生。通过结合间隙锁和记录形成 **next-key lock**,可以实现更严格的隔离级别——可重复读 (Repeatable Read)[^3]。 #### 二、间隙锁的工作方式 间隙锁的作用对象是两个相邻索引值之间形成的逻辑间隔区域。例如,在表 `t` 中存在如下索引值序列 `{10, 20, 30}`,那么可能存在的间隙包括 `(负无穷, 10)`、`(10, 20)` 和 `(20, 30)` 等。如果某条 SQL 查询语句指定了一个范围条件,则该操作可能会触发间隙锁的应用: ```sql SELECT * FROM t WHERE id BETWEEN 15 AND 25 FOR UPDATE; ``` 上述例子中,假设当前仅有两条记录分别对应 ID 值为 10 和 30 的情况,执此命令后不仅会对实际查找到的数据上排他,同时也会覆盖整个 `(10, 30)` 范围内的所有潜在位置设置间隙锁[^2]。 需要注意的是,间隙锁本身并不影响已经存在于数据库中的具体元组实例;它的核心功能在于控制未被占用的空间部分,确保不会因外部干扰而导致一致性破坏。 #### 三、Next-Key Lock 组成分析 正如前面提到过的那样,默认情况下 InnoDB 使用一种称为 Next-Key Lock 的组合形式来进资源保护。其结构由两部分内容共同构成: - **Record Lock**: 针对确切的目标实体实施独占或者共享权限管理; - **Gap Lock**: 对围绕目标周围的空白领域以约束限制。 因此每一个单独的 Next-Key Lock 实际上代表了一个半开放式的区间表达式 `[start_key, end_key)` ,其中 start_key 表示起始边界点而 end_key 则表示结束界限但不含自身成员参与计算过程之中。 #### 四、适用场景举例说明 以下是几个典型应用案例展示如何利用 Gap Lock 提升系统性能以及保障业务逻辑准确性: ##### 场景 A: 库存管理系统 在一个电商网站后台维护商品库存数量的过程中,为了避免多个订单同时扣减相同货物造成超卖风险,可以通过显式声明意向更新指令提前占据相应批次号段位,进而减少竞争冲突概率。 ```sql -- 占用编号介于100至200间的全部可用货品 LOCK TABLES products WRITE; START TRANSACTION; SELECT stock_quantity FROM products WHERE product_id >= 100 AND product_id < 200 FOR UPDATE; UPDATE products SET stock_quantity = stock_quantity - purchased_amount WHERE ... ; COMMIT; UNLOCK TABLES; ``` 此处采用 FOR UPDATE 关字强制获取相关联区段上的写入许可权柄,间接激活了底层 GAP LOCK 控制策略. ##### 场景 B: 时间轴预约平台 设想构建一款在线日程安排工具允许用户自挑选空闲时段预定会议室等活动场地。此时借助于高效能的关系型数据库解决方案能够轻松达成预期效果的同时兼顾用户体验流畅度需求. 假设有这样一张存储预订详情的基础表格 designates(id INT PRIMARY KEY AUTO_INCREMENT,start_time DATETIME NOT NULL,end_time DATETIME NOT NULL),我们可以编写类似下面这样的验证函数用来检测是否存在重叠时间段冲突状况发生 : ```sql CREATE FUNCTION check_overlap(new_start DATETIME,new_end DATETIME) RETURNS BOOLEAN DETERMINISTIC BEGIN RETURN EXISTS ( SELECT 1 FROM designates d WHERE new_start < d.end_time AND new_end > d.start_time); END$$ DELIMITER ; INSERT INTO designates(start_time ,end_time ) VALUES('2024-07-08 09:00','2024-07-08 11:00') AS NEW IF NOT(check_overlap('2024-07-08 09:00','2024-07-08 11:00')); ``` 这里巧妙运用到了基于时间戳字段建立起来的复合唯一性约束配合自定义辅助方法完成初步筛查过滤工作之后再进一步提交最终确认动作之前再次进全面扫描排查任何可能出现的新旧事件交叉情形。由于涉及到连续数值比较运算所以必然伴随着相应的 GAPS LOCKING 操作介入进来保驾护航. ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值