每日一篇高频面试题系列之【MySQL 锁】

文章目录

  • [每日一篇高频面试题系列之【MySQL 锁】](#每日一篇高频面试题系列之【MySQL 锁】)
    • 前言
    • 一、面试经典原题
    • [二、MySQL 锁完整体系分类](#二、MySQL 锁完整体系分类)
      • [1. 按锁粒度分](#1. 按锁粒度分)
      • [2. 按锁(读写)类型分](#2. 按锁(读写)类型分)
      • [3. 按锁算法分(InoDB核心)](#3. 按锁算法分(InoDB核心))
      • [4. 意向锁(表级辅助锁)](#4. 意向锁(表级辅助锁))
      • [5. 其他高频锁](#5. 其他高频锁)
      • 6.显示锁与隐式锁
      • 总结
    • [三、每种锁原理 + 实现方式 + 使用场景](#三、每种锁原理 + 实现方式 + 使用场景)
      • 1、表锁
      • 2、行锁(记录锁)
      • [3、共享锁 S / 排他锁 X](#3、共享锁 S / 排他锁 X)
      • [4、意向锁 IS / IX](#4、意向锁 IS / IX)
      • [5、间隙锁 Gap Lock](#5、间隙锁 Gap Lock)
      • [6、临键锁 Next-Key Lock](#6、临键锁 Next-Key Lock)
      • [7、MDL 元数据锁](#7、MDL 元数据锁)
      • [8、AUTO-INC 自增锁](#8、AUTO-INC 自增锁)
    • 四、高频必背面试问答题
      • [1. InnoDB 行锁为什么依赖索引?](#1. InnoDB 行锁为什么依赖索引?)
      • [2. 哪些情况行锁会降级为表锁?](#2. 哪些情况行锁会降级为表锁?)
      • [3. RC 和 RR 在锁上最大区别?](#3. RC 和 RR 在锁上最大区别?)
      • [4. 临键锁什么时候降级为记录锁?](#4. 临键锁什么时候降级为记录锁?)
      • [5. MySQL 死锁产生的四个必要条件](#5. MySQL 死锁产生的四个必要条件)
      • [6. 如何避免 MySQL 死锁?](#6. 如何避免 MySQL 死锁?)
      • [7. 怎么排查 MySQL 死锁?](#7. 怎么排查 MySQL 死锁?)
      • [8. 意向锁能不能人工手动加?](#8. 意向锁能不能人工手动加?)
      • [9. 共享锁和排他锁能否混用?](#9. 共享锁和排他锁能否混用?)
      • [10. 间隙锁会不会阻塞 update、delete?](#10. 间隙锁会不会阻塞 update、delete?)
    • [五、30 秒面试万能背诵版](#五、30 秒面试万能背诵版)
    • 六、小测验

每日一篇高频面试题系列之【MySQL 锁】

适合:春招 / 跳槽 / 转行 | 级别:Java 中初级开发 | 难度:⭐⭐⭐⭐ | 频率:极高


前言

关注公众号 "知识汲取者"【Java 面试题】合集,可以每天抽空五分钟,趁着坐车、蹲坑、摸鱼等琐碎时间看一看,一来可以扎实基本功 ,二来可以随时熟悉面试题,让我们始终保持拥有随时可面的状态,时刻保持危机意识。

本专栏适合人群:

  1. 在职的 Java 开发
  2. 准备或正在跳槽的 Java 开发
  3. 未来想从事 Java 开发

欢迎关注公众号


一、面试经典原题

  1. MySQL InnoDB 有哪些锁?分类有哪些?
  2. 表锁、行锁、意向锁、间隙锁、临键锁原理、实现方式和区别?
  3. 行锁什么时候会降级为表锁?
  4. 共享锁、排他锁、意向锁兼容规则?
  5. 间隙锁、临键锁解决了什么问题?RC 和 RR 下有什么区别?
  6. MySQL 死锁产生原因、如何避免、怎么排查?

PS:如果你对于上述 MySQL 的高频面试题不是特别熟悉,可以通过阅读二、三章节进行学习,同时完成四、六章节的题目,如果觉得二、三章节内容太多记不住,想快速记忆就阅读五章节


二、MySQL 锁完整体系分类

1. 按锁粒度分

  • 表级锁

    • 核心特性:锁定整张表。开销小、加锁快,不会出现死锁,但锁粒度最大,发生锁冲突的概率最高,并发度最低
    • 触发方式 :通过 LOCK TABLES 表名 READ/WRITE 显式加锁;或在执行 ALTER TABLEDROP TABLE 等 DDL 语句时由系统自动触发
    • 适用场景:适用于全表扫描、批量更新整张表数据,或者对并发要求不高的离线业务处理
  • 行级锁

    • 核心特性:锁定单行或多行索引记录。开销大、加锁慢,可能出现死锁,但锁粒度最小,发生锁冲突的概率最低,并发度最高
    • 触发方式 :在执行 SELECT ... FOR UPDATEINSERTUPDATEDELETE 等语句时,通过索引条件精准定位并自动触发
    • 适用场景:高并发的 OLTP(在线事务处理)系统,如电商下单、库存扣减、账户转账等核心业务
  • 页级锁

    • 核心特性:锁定相邻的一组记录(数据页)。开销和加锁时间介于表锁和行锁之间,会出现死锁,并发度一般
    • 触发方式:由存储引擎(如早期的 BerkeleyDB)在操作数据页时自动触发
    • 适用场景:现代 MySQL 业务中已极少使用,多见于一些特定的历史存储引擎或特殊场景

2. 按锁(读写)类型分

  • 共享锁(S 锁 / 读锁)

    • 核心特性:遵循"大家一起读,不准改"的原则。允许多个事务同时对同一份数据加 S 锁并读取(读读兼容);但只要有一个事务持有 S 锁,其他事务就无法对该数据加排他锁(X锁),即不能修改(读写互斥)
    • 触发方式 :通过手动执行 SELECT ... LOCK IN SHARE MODE(或 MySQL 8.0+ 的 SELECT ... FOR SHARE)显式添加
    • 适用场景:需要保证在读取数据期间,数据不会被其他事务修改,但允许其他人同时读取的场景(如读取并校验关键配置数据)
  • 排他锁(X 锁 / 写锁)

    • 核心特性:遵循"我一个人改,别人不准碰"的原则。同一时间只能有一个事务对某份数据加 X 锁。一旦加上,其他任何事务都无法再对该数据加 S 锁(不能读)或 X 锁(不能改),完全独占数据
    • 触发方式 :所有的写操作(INSERTUPDATEDELETE)会自动加上 X 锁;也可以通过手动执行 SELECT ... FOR UPDATE 显式添加
    • 适用场景:涉及数据修改、删除或需要强一致性独占读取的场景(如秒杀扣库存、余额修改)

3. 按锁算法分(InoDB核心)

  • 记录锁(Record Lock)

    • 核心特性:最基础的行级锁,精准锁住某一条索引记录,确保在锁持有期间,其他事务无法修改或删除该条记录
    • 触发方式 :在唯一索引(如主键)上进行等值查询并加锁(如 WHERE id = 1 FOR UPDATE)时触发
    • 适用场景:精准更新或删除某一条特定记录的业务操作
  • 间隙锁(Gap Lock)

    • 核心特性:锁住索引记录之间的间隙(左开右开区间),不锁记录本身。核心目的是防止其他事务在这个间隙中插入新记录,从而彻底解决"幻读"问题
    • 触发方式 :在普通索引进行等值或范围查询,以及主键/唯一索引进行范围查询(如 BETWEEN>)时触发
    • 适用场景:在可重复读(RR)隔离级别下,防止范围查询时出现幻读,保证数据的一致性视图
  • 临键锁(Next-Key Lock)

    • 核心特性:记录锁 + 间隙锁的组合,锁定左开右闭区间。这是 InnoDB 在 RR 隔离级别下的默认行锁算法,既锁住记录本身,又锁住前面的间隙
    • 触发方式:InnoDB 在 RR 隔离级别下进行范围查询或普通索引查询时,默认自动使用此算法加锁
    • 适用场景:MySQL 默认的 RR 隔离级别下,绝大多数涉及索引范围扫描的加锁场景,从根源上杜绝幻读

4. 意向锁(表级辅助锁)

  • 意向共享锁(IS)

    • 核心特性:一种表级别的"预告锁",表示事务意图对表中的某些行加共享锁(S锁)。它与表级共享锁兼容,与表级排他锁互斥
    • 触发方式 :在执行 SELECT ... LOCK IN SHARE MODE 前,数据库会自动先在表级别加上 IS 锁
    • 适用场景:提高加表锁时的效率。让数据库在需要给整张表加锁时,只需检查表上有没有意向锁,而无需遍历全表检查每一行
  • 意向排他锁(IX)

    • 核心特性:一种表级别的"预告锁",表示事务意图对表中的某些行加排他锁(X锁)。它与任何表级锁(S锁和X锁)都互斥
    • 触发方式 :在执行 SELECT ... FOR UPDATEINSERTUPDATEDELETE 前,会自动加上 IX 锁
    • 适用场景:同 IS 锁,主要用于快速判断表内是否有行被加锁,避免全表扫描带来的性能损耗

5. 其他高频锁

  • 自增锁(AUTO-INC)

    • 核心特性:一种特殊的表级锁。在插入数据时锁定自增计数器,保证生成的自增值是唯一且连续的(在高并发模式下会采用轻量级锁来平衡性能与连续性)
    • 触发方式:当向带有自增主键(AUTO_INCREMENT)的表中插入数据时自动触发
    • 适用场景:依赖自增主键生成唯一连续 ID 的表插入操作
  • 元数据锁(MDL)

    • 核心特性:由 MySQL Server 层管理的锁,用于保护表结构等元数据信息。DML 操作加 MDL 读锁,DDL 操作加 MDL 写锁,确保读写互斥、写写互斥
    • 触发方式:对表进行任何增删改查(DML)或表结构变更(DDL)时,由系统自动触发
    • 适用场景 :防止在查询或修改数据时,表结构被意外修改(如查询时有人执行了 ALTER TABLE),保障元数据的安全与一致性

6.显示锁与隐式锁

在 MySQL 的锁机制中,我们可以根据**"是否需要开发者手动写 SQL 语句干预",将这些锁清晰地划分为"开发者可主动操作"的 显式锁和"数据库自动管理"的隐式锁**两大类

  • 显示锁:这类锁需要你在写 SQL 语句时,通过特定的语法手动加上。通常用于在复杂业务中,为了保证数据的一致性而进行提前加锁(悲观锁)
  • 隐式锁:这类锁由 MySQL 存储引擎(InnoDB)或 Server 层在后台自动维护,开发者无法直接通过 SQL 命令去"加"或"释放"它们,只需要了解它们的触发机制即可

总结

锁分类维度 锁名称 核心特性 触发方式 适用场景 操作属性
按锁粒度 表级锁 锁定整张表,开销小、无死锁,但并发度最低 LOCK TABLES 显式加锁;或执行 DDL 语句自动触发 全表扫描、批量更新、离线业务处理 可主动操作
行级锁 锁定单行/多行,开销大、有死锁,但并发度最高 通过索引条件精准定位,执行增删改查时自动触发 高并发的 OLTP 系统(如电商下单、转账) 数据库自动管理
页级锁 锁定数据页,开销和并发度介于表锁与行锁之间 由特定存储引擎在操作数据页时自动触发 现代业务极少使用(多见于早期存储引擎) 数据库自动管理
按读写类型 共享锁 (S锁) "大家一起读,不准改",读读兼容,读写互斥 SELECT ... LOCK IN SHARE MODE / FOR SHARE 读取并校验关键数据,防止读取期间被篡改 可主动操作
排他锁 (X锁) "我一个人改,别人不准碰",写读、写写均互斥 INSERT/UPDATE/DELETE 自动触发;或 SELECT ... FOR UPDATE 数据修改、删除,或需独占读取的防并发场景 可主动操作/自动管理
按锁算法 记录锁 精准锁住某一条索引记录 在唯一索引上进行等值查询并加锁时触发 精准更新或删除某一条特定记录 数据库自动管理
间隙锁 锁住索引之间的间隙(左开右开),防插入 普通索引等值/范围查询,或主键范围查询时触发 RR 隔离级别下,防止范围查询出现幻读 数据库自动管理
临键锁 记录锁+间隙锁(左开右闭),RR级别默认算法 RR 隔离级别下进行范围或普通索引查询时默认使用 绝大多数涉及索引范围扫描的加锁场景 数据库自动管理
意向锁 意向共享锁(IS) 表级"预告锁",意图对某些行加 S 锁 执行 SELECT ... LOCK IN SHARE MODE 前自动加锁 提升加表锁时的效率,避免全表遍历检查 数据库自动管理
意向排他锁(IX) 表级"预告锁",意图对某些行加 X 锁 执行 SELECT ... FOR UPDATE、增删改前自动加锁 提升加表锁时的效率,避免全表遍历检查 数据库自动管理
其他高频锁 自增锁 特殊的表级锁,锁定自增计数器保证唯一连续 向带自增主键的表插入数据时自动触发 依赖自增主键生成唯一连续 ID 的插入操作 数据库自动管理
元数据锁(MDL) Server层锁,保护表结构等元数据,防读写冲突 访问表(DML)或修改表结构(DDL)时自动触发 防止查询时表结构被意外修改,保障元数据安全 数据库自动管理

三、每种锁原理 + 实现方式 + 使用场景

1、表锁

  • 实现方式

    • 作用在整张数据表,不依赖索引
    • MyISAM 默认引擎锁
    • InnoDB 手动可加:lock tables 表 read/write
  • 特点

    • 加锁快、开销小、无死锁
    • 粒度大、并发低
    • 写锁阻塞所有读写
  • 适用场景:全表备份、批量导入、DDL 变更、临时全局锁控制


2、行锁(记录锁)

  • 实现方式

    • InnoDB 基于索引实现
    • 只锁定索引对应的行记录
    • 不走索引 → 行锁直接降级为表锁
  • 触发 SQL

    sql 复制代码
    -- 排他行锁
    select * from t where id=1 for update;
    update t set name='' where id=1;
    delete t where id=1;
    
    -- 共享行锁
    select * from t where id=1 lock in share mode;
  • 特点

    • 粒度最小、并发最高
    • 依赖主键 / 唯一索引生效
    • 容易产生死锁

3、共享锁 S / 排他锁 X

  • 共享锁 S(读锁)

    • 事务加读锁,自己可读、可加共享锁
    • 其他事务可读、不能加写锁
    • 语法:lock in share mode
  • 排他锁 X(写锁)

    • 独占锁,自己可读写
    • 其他事务既不能读也不能写
    • update、delete、for update 自动加 X 锁
  • 兼容规则(面试必背)

    S 共享锁 X 排他锁
    S 兼容 互斥
    X 互斥 互斥

4、意向锁 IS / IX

  • 实现方式

    • 属于表级锁,自动由 InnoDB 维护,人工不能手动加
    • 事务准备加行锁前,先在表上加意向锁
  • 作用:不用遍历全表每一行判断锁状态,快速判断表是否有冲突表锁,提升加锁效率。

    • IS:意向共享,准备给行加 S 锁
    • IX:意向排他,准备给行加 X 锁
  • 兼容规则

    • 意向锁之间互相兼容
    • 只要表上有 S/X 表锁,就阻塞后续所有 IS/IX

5、间隙锁 Gap Lock

  • 实现方式

    • 仅 RR 可重复读 隔离级别存在
    • RC 级别关闭间隙锁
    • 锁定两条索引之间的空隙,不锁定已有记录
  • 核心作用 :阻止其他事务在间隙 insert 新数据,规避幻读

  • 触发场景:范围查询 + 当前读(for update /update 范围条件)


6、临键锁 Next-Key Lock

  • 实现方式

    • InnoDB RR 默认锁算法
    • 结构:临键锁 = 记录锁 + 间隙锁
    • 锁住左开右闭索引区间
  • 作用 :既锁住已有行,又锁住前后间隙,最大程度抑制幻读

  • 什么时候退化成普通行锁

    条件命中唯一索引 / 主键 精准等值匹配,临键锁降级为单纯记录锁,不再加间隙锁。


7、MDL 元数据锁

  • 实现方式

    • 访问表时自动加,保护表结构不被中途修改。
    • 读 MDL:多个事务共享
    • 写 MDL:排他,阻塞所有读写
  • 面试高频坑:长事务不提交,持有 MDL 读锁,导致 DDL 一直阻塞。


8、AUTO-INC 自增锁

  • 实现
    • 插入自增列时加锁,保证自增值连续唯一。
    • 批量插入有不同锁策略,影响性能和自增间隙。

四、高频必背面试问答题

1. InnoDB 行锁为什么依赖索引?

行锁是索引锁,MySQL 必须通过索引定位到具体某一行;

如果没有索引,无法精准锁定行,只能锁整张表,行锁降级为表锁

2. 哪些情况行锁会降级为表锁?

  1. 没有命中任何索引
  2. 索引失效(函数、隐式类型转换、like % 前缀)
  3. 范围查询不走唯一索引,临键锁范围过大,等价锁全表

3. RC 和 RR 在锁上最大区别?

  • RC:无间隙锁、无临键锁,只有记录锁;每次查询刷新快照,无法防幻读
  • RR:有间隙锁 + 临键锁,配合 MVCC,最大程度规避幻读

4. 临键锁什么时候降级为记录锁?

精准等值匹配唯一索引 / 主键,直接锁定单行,不需要间隙保护,退化成普通行锁。

5. MySQL 死锁产生的四个必要条件

  1. 互斥条件
  2. 不可剥夺
  3. 请求保持
  4. 循环等待

6. 如何避免 MySQL 死锁?

  1. 统一访问表和行的顺序
  2. 小事务,尽早提交
  3. 避免长事务
  4. 合理加索引,缩小锁范围
  5. 业务加分布式锁替代数据库锁

7. 怎么排查 MySQL 死锁?

  1. 开启死锁日志:show engine innodb status;
  2. 查看 LATEST DETECTED DEADLOCK
  3. 分析两条事务加锁顺序、SQL、索引情况

8. 意向锁能不能人工手动加?

不能,InnoDB 内部自动维护,用户无法手动操作意向锁。

9. 共享锁和排他锁能否混用?

可以,但遵循兼容规则;一旦有一方加 X 锁,全部互斥阻塞。

10. 间隙锁会不会阻塞 update、delete?

不会,间隙锁只锁空隙,不锁已有记录;

已有行的修改不受间隙锁影响,只阻塞 insert。


五、30 秒面试万能背诵版

  • 按粒度分表锁、行锁;

  • 按算法分记录锁、间隙锁、临键锁,还有意向锁、MDL、自增锁

  • 表锁粒度大并发低;行锁基于索引,无索引会降级表锁;

  • 共享锁可读不可改,排他锁独占读写;

  • 意向锁是表级辅助锁,自动维护,加速锁冲突判断;

  • RR 级别有间隙锁和临键锁,间隙锁锁空隙防插入,临键锁是行锁加间隙锁,规避幻读;

  • RC 没有间隙锁;统一访问顺序、短事务、合理建索引可以避免死锁。


六、小测验

  1. 简述表锁、行锁、意向锁、间隙锁、临键锁区别?
  2. 什么情况下行锁会降级为表锁?
  3. RC 和 RR 在间隙锁、临键锁上有什么差异?
  4. 死锁产生四个条件?如何排查和避免?
  5. 临键锁什么时候会退化成普通记录锁?

点赞 + 收藏,每天 5 分钟,面试稳稳上岸 ✨

相关推荐
老纪1 小时前
SQL中如何查找特定的空值行:WHERE IS NULL深度解析
jvm·数据库·python
麦聪聊数据1 小时前
数据 API 平台选型:深度解读数据服务的四大关键技术与架构底座
数据库·sql
IT研究所1 小时前
AI 时代下的知识管理:从 Claude 的“复盘”能力看生成式 AI价值
大数据·运维·数据库·人工智能·科技·低代码·自然语言处理
2301_781571422 小时前
mysql数据库响应缓慢如何排查_使用EXPLAIN分析执行计划
jvm·数据库·python
彳亍1012 小时前
实现倒计时数字在到达1后自动隐藏(2为最后可见数字),同时继续运行至-1再终止
jvm·数据库·python
lolo大魔王2 小时前
Go 后端实战|Gin + GORM V2 + MySQL 企业级 API 项目开发(完整版)
mysql·golang·gin
Hical_W2 小时前
Hical 踩坑实录五部曲(五):Boost.MySQL 协程集成的 5 个坑
数据库·mysql·开源
X56612 小时前
CSS如何处理SSR中CSS引入_在服务端渲染时提取关键CSS
jvm·数据库·python
哆哆啦003 小时前
使用 Obsidian + GitHub Actions + GitHub Pages 搭建内容发布流
数据库·笔记·github·obsidian