当前位置: 首页 > news >正文

关于 MySQL 的锁,你真的分清楚了吗?

关于 MySQL 的锁,你真的分清楚了吗?

MySQL 的锁机制是保证数据库在并发环境下数据一致性和完整性的核心。理解锁对于优化 SQL 性能、避免死锁以及设计高并发系统至关重要。

以下我将从锁的粒度、锁的类型、InnoDB 引擎的锁算法、隔离级别与锁的关系、以及死锁与优化这几个维度详细讲解。


一、锁的粒度 (Lock Granularity)

锁的粒度决定了锁住数据范围的大小。粒度越大,并发度越低,但开销越小;粒度越小,并发度越高,但开销越大。

1. 表级锁 (Table Lock)
  • 特点:开销小,加锁快,不会出现死锁。但锁定粒度大,发生锁冲突的概率最高,并发度最低。
  • 适用场景:MyISAM 引擎默认使用表锁;InnoDB 在某些特定情况(如全表扫描无索引)下也会退化为表锁。
  • 类型
    • 表共享读锁 (Table Read Lock):其他事务可以读,但不能写。
    • 表独占写锁 (Table Write Lock):其他事务不能读也不能写。
2. 行级锁 (Row Lock)
  • 特点:开销大,加锁慢,会出现死锁。但锁定粒度最小,发生锁冲突的概率最低,并发度最高。
  • 适用场景InnoDB 引擎支持行锁。
  • 注意:InnoDB 的行锁是锁在索引上的。如果 SQL 语句没有走索引,InnoDB 会升级为表锁。
3. 页级锁 (Page Lock)
  • 特点:介于表锁和行锁之间。一次锁定相邻的一组记录。
  • 适用场景:BDB 引擎(现在很少用),MySQL 主流是 InnoDB(行锁)和 MyISAM(表锁)。

二、锁的模式 (Lock Modes)

主要针对 InnoDB 引擎,分为两大类:

1. 共享锁 (Shared Lock, S 锁)
  • 含义:又称读锁。允许事务读一行数据。
  • 兼容性:一个事务获取了 S 锁,其他事务也可以获取 S 锁,但不能获取 X 锁。
  • SQL 示例SELECT ... LOCK IN SHARE MODE(MySQL 8.0 后改为SELECT ... FOR SHARE)。
2. 排他锁 (Exclusive Lock, X 锁)
  • 含义:又称写锁。允许事务更新或删除一行数据。
  • 兼容性:一个事务获取了 X 锁,其他事务不能获取 S 锁或 X 锁。
  • SQL 示例UPDATE,DELETE,INSERT,SELECT ... FOR UPDATE
3. 意向锁 (Intention Lock)
  • 含义:表级锁。InnoDB 支持多粒度锁定,为了快速判断表中是否有行锁,引入了意向锁。
  • 类型
    • 意向共享锁 (IS):事务打算给数据行加 S 锁。
    • 意向排他锁 (IX):事务打算给数据行加 X 锁。
  • 作用:如果有人在表上加了表级 X 锁,InnoDB 会检查是否有 IS/IX 锁。如果有,说明有人在用行锁,表锁申请需等待。这避免了遍历所有行来判断是否可加表锁。

三、InnoDB 的锁算法 (核心难点)

InnoDB 实现了以下三种行锁算法,这是面试和实际开发中最容易出问题的地方。

1. 记录锁 (Record Lock)
  • 定义:锁定索引记录本身。
  • 场景SELECT ... FOR UPDATE查询唯一索引的等值匹配。
  • 注意:如果表没有索引,InnoDB 会使用隐藏的行 ID 进行记录锁(实际上等同于锁全表)。
2. 间隙锁 (Gap Lock)
  • 定义:锁定索引记录之间的间隙,或者第一条记录之前、最后一条记录之后的间隙。不包含记录本身
  • 目的:防止幻读(Phantom Read)。即防止其他事务在间隙中插入新数据。
  • 场景:范围查询(Range Query)。例如WHERE id > 10 AND id < 20
  • 副作用:间隙锁会阻塞其他事务在间隙中INSERT数据,严重影响并发插入性能。
3. 临键锁 (Next-Key Lock)
  • 定义记录锁 + 间隙锁。锁定索引记录本身以及之前的间隙。
  • 场景:默认情况下,InnoDB 在Repeatable Read (RR)隔离级别下,使用非唯一索引进行等值或范围查询时,会使用 Next-Key Lock。
  • 目的:同时防止修改已有数据和插入新数据(解决幻读)。

四、隔离级别与锁的关系

MySQL 有四种隔离级别,锁的行为大不相同:

隔离级别脏读不可重复读幻读锁的行为特点
Read Uncommitted可能可能可能几乎不加锁,性能最高,数据最不安全。
Read Committed (RC)不可能可能可能快照读不加锁。当前读只加 Record Lock,不加 Gap Lock。并发度高。
Repeatable Read (RR)不可能不可能不可能默认级别当前读默认使用 Next-Key Lock (Record + Gap),防止幻读。
Serializable不可能不可能不可能所有读操作都加锁,相当于串行执行,性能极低。

关键区别 (RC vs RR):

  • RC级别下,SELECT ... FOR UPDATE如果查询id = 10,只锁住id=10这一行。
  • RR级别下,同样的查询,如果id不是唯一索引,可能会锁住id=10以及它周围的间隙(Next-Key Lock),防止别人插入id=10附近的数据。

五、常见锁问题与死锁

1. 死锁 (Deadlock)
  • 定义:两个或多个事务互相持有对方需要的锁,并等待对方释放,形成循环等待。
  • 经典案例
    • 事务 A:锁住行 1,想锁行 2。
    • 事务 B:锁住行 2,想锁行 1。
  • InnoDB 处理:检测到死锁后,会回滚其中一个事务(通常是回滚代价较小的那个)。
  • 避免策略
    • 保持多个表/行的访问顺序一致。
    • 大事务拆分成小事务。
    • 在 RC 隔离级别下(减少 Gap Lock)。
    • 使用唯一索引查询(避免 Next-Key Lock 退化为 Gap Lock)。
2. 锁等待 (Lock Wait)
  • 事务请求锁时,如果锁被占用,会进入等待状态。超过innodb_lock_wait_timeout(默认 50 秒) 会报错。

六、如何查看与分析锁

1. 查看正在等待锁的事务
-- MySQL 5.7+ / 8.0SELECT*FROMperformance_schema.data_lock_waits;
2. 查看当前持有的锁
-- MySQL 8.0+SELECT*FROMperformance_schema.data_locks;
3. 查看死锁日志
SHOWENGINEINNODBSTATUS;-- 在输出结果中寻找 "LATEST DETECTED DEADLOCK" 部分
4. 查看锁等待情况 (Sys 库)
SELECT*FROMsys.schema_table_lock_waits;

七、锁优化最佳实践

  1. 尽可能使用索引

    • InnoDB 行锁是锁在索引上的。如果不走索引,行锁会升级为表锁,导致性能急剧下降。
    • 使用EXPLAIN检查 SQL 是否命中索引。
  2. 缩小锁范围

    • 只更新必要的行,避免全表更新。
    • 将大事务拆分为小事务,尽快提交(Commit),释放锁。
  3. 降低隔离级别 (如果业务允许)

    • 将 RR 降级为 RC。RC 级别下没有 Gap Lock,并发插入性能更好,且能减少死锁概率。
  4. 避免范围查询加锁

    • 在 RR 级别下,范围查询(>,<,BETWEEN)会触发 Gap Lock 或 Next-Key Lock,阻塞插入。如果可能,改为等值查询。
  5. 固定访问顺序

    • 如果业务逻辑需要同时更新多行或多表,确保所有事务都按照相同的顺序访问资源,这是避免死锁最有效的方法。
  6. 使用SELECT ... FOR UPDATE需谨慎

    • 确保查询条件走唯一索引。
    • 如果只是为了防并发修改,考虑使用乐观锁(CAS 机制,如version字段)。

总结

  • MyISAM只有表锁,InnoDB支持行锁。
  • InnoDB 行锁依赖于索引,无索引则锁全表。
  • RR 隔离级别下,非唯一索引的查询会加Next-Key Lock(包含间隙),容易导致性能问题和死锁。
  • RC 隔离级别下,只加Record Lock,并发更好,是互联网高并发场景的推荐选择。
  • 排查锁问题主要靠SHOW ENGINE INNODB STATUSperformance_schema表。

理解这些机制,相信你不仅是一个八股小能手,更是一位数据库Infra 大神。

http://www.jsqmd.com/news/482166/

相关文章:

  • 实现大数据领域数据合规的策略指南
  • 基于双层共识控制的直流微电网优化调度附Matlab代码
  • java学习第三天
  • 【单调栈】LeetCode 42. 接雨水
  • 基于随机奇异值分解和软阈值的大数据集中健壮高效的谐波去噪附Matlab代码
  • 如何从互联网上免费下载歌曲
  • 分片请求视频,然后播放,能解决视频文件超大导致浏览器崩溃卡死的问题吗?
  • 什么是前置mp4?
  • 基于天牛群算法优化ELM的功率预测研究附Matlab代码
  • 基于鹈鹕优化算法(POA)的支持向量机(SVM)时序预测模型研究附Matlab代码
  • 当麻雀学会三角函数:SCSSA-BiLSTM分类模型实战手记
  • 第七章 回溯算法part01
  • 数字员工和AI销冠系统是什么?它们在企业智能化运营中的优势与应用是什么?
  • 基于线性准则的考虑风力发电不确定性的分布鲁棒优化机组组合附Matlab代码
  • 公共数据资源挖掘:TCGA、GEO、ENCODE、GTEx——如何利用公开数据开展二次研究?
  • “土木人转行软件测试学习第10天”-流程管理平台(JIRA)
  • 2026年3月亲子西双版纳住宿推荐,这些地方值得一住!目前排行前列的西双版纳住宿源头厂家有哪些聚焦优质品牌综合实力排行 - 品牌推荐师
  • 本月刮板输送机产品排名,看看哪些表现突出,排行前列的刮板输送机排行综合实力与口碑权威评选 - 品牌推荐师
  • 微信JS-SDK分享权限验证失败?“offline verifying”错误排查全攻略
  • 速看!2026年3月刮板输送机优质产品排行榜,市面上头部刮板输送机厂商优质品牌榜单更新 - 品牌推荐师
  • 文件头标识
  • 2026年3月国内口碑好的皮带输送机生产厂家排行榜大揭秘,皮带输送机生产厂家关键技术和产品信息全方位测评 - 品牌推荐师
  • Gradle 与 React Native:跨平台移动开发的构建指南
  • 【电力系统】新能源出力不确定性的电气设备综合能源系统协同优化【含Matlab源码 15175期】
  • 微短剧《嘉庆君游台湾》开机 演员余玥演绎进阶版菊香
  • 详解DeepSeek残差链接mHC进化之路
  • BookRAG:面向层级文档的树-图融合RAG框架
  • 2026年国内这些口碑好的皮带输送机生产厂家上榜啦,目前皮带输送机企业哪个好精选优质品牌解析 - 品牌推荐师
  • 2026年口碑聚焦:皮带输送机生产厂家实力大盘点,皮带输送机公司排行榜技术领航者深度解析 - 品牌推荐师
  • 用STM32+LAN9252实现etherCAT 从站IO控制