锁机制(Locking):解决数据库“死锁”与“阻塞”的终极指南

本文涉及的产品
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
云数据库 PolarDB MySQL 版,列存表分析加速 8核16GB
RDS DuckDB + QuickBI 企业套餐,8核32GB + QuickBI 专业版
简介: 数据库小学妹带你轻松掌握锁机制!🔒 详解行锁/表锁、共享锁/排他锁、记录/间隙/临键锁,剖析死锁成因与避坑技巧(如索引缺失、长事务、间隙锁副作用),附MySQL实战命令。

📌 今日关键词:​​ 锁机制、死锁、锁等待、并发控制、行锁、表锁

大家好呀!我是​数据库小学妹​👋

我们之前学过事务,知道事务可以把多个操作打包,保证要么全成功要么全失败。但是,你有没有想过:

当两个人同时修改同一条数据——比如双十一抢购最后一件商品,A用户下单库存减1,B用户也同时下单——数据库怎么保证库存不会变成负数?怎么避免两个人的操作互相覆盖?

这就是的职责。锁就像数据库里的交通警察,控制着谁可以访问数据、谁需要等待,保证并发操作下数据依然正确。

今天,我们要学习数据库进阶路上的​“交通规则”——锁机制(Locking)​!🚦,让你理解数据库背后的“并发控制”原理,写代码时少踩死锁的坑!

一、什么是锁机制?—— 数据库的“红绿灯”

想象一下,如果数据库是一个巨大的图书馆,成千上万的读者(并发请求)同时想借书、还书。如果没有管理员,大家一拥而上,书就会被撕烂或者拿错。

锁机制就是数据库的管理员,它通过给数据加上“锁”,来保证在并发环境下,数据的一致性和完整性。

📌核心价值:

  • 防止脏读: 读到了别人还没提交的脏数据。
  • 防止不可重复读: 同一个事务里,两次读取的数据不一致。
  • 防止幻读: 刚读完数据,别人就插了一条新数据进来。

🔍如何查看?

在MySQL中,我们可以通过以下命令查看锁的状态:

-- 查看当前的进程(谁在阻塞谁)
SHOW PROCESSLIST;

-- 查看最近一次死锁的信息(侦探现场)
SHOW ENGINE INNODB STATUS;

二、锁的分类(新手先掌握这些)

按粒度分:表锁 vs 行锁

类型 特点 适用引擎 并发性能
表锁 锁定整张表,其他事务不能读写 MyISAM、MEMORY
行锁 只锁定某一行,其他行可并发操作 InnoDB(默认)

InnoDB默认使用行锁​,这也是为什么生产环境推荐InnoDB的原因。

按模式分:共享锁(S锁)vs 排他锁(X锁)

锁类型 别名 作用 兼容性
共享锁 读锁 允许其他事务同时读,但不能写 多个共享锁可共存
排他锁 写锁 禁止其他事务读和写 不与其他任何锁共存

自动加锁规则:

  • SELECT ... 不加锁(快照读)
  • SELECT ... FOR UPDATE 加行级排他锁
  • SELECT ... LOCK IN SHARE MODE 加行级共享锁
  • UPDATEDELETEINSERT 自动加行级排他锁

三、行锁的三种具体形式(InnoDB)

锁类型 锁定范围 触发条件
记录锁 锁定单条记录 WHERE id = 1 且id是唯一索引/主键
间隙锁 锁定一个范围(不包含记录) WHERE id BETWEEN 1 AND 10 且id不是唯一索引
临键锁 锁定一个范围+记录 默认的间隙锁变种(防止幻读)

间隙锁是InnoDB在可重复读隔离级别下防止幻读的关键。它锁定的“不存在”的行,防止其他事务插入到该范围。

四、什么是死锁?怎么避免?

​死锁​:两个或多个事务互相等待对方释放锁,导致谁也进行不下去。

⏳经典死锁场景:

-- 事务A
BEGIN;
UPDATE account SET balance = balance - 100 WHERE id = 1;  -- 锁住id=1
UPDATE account SET balance = balance + 100 WHERE id = 2;  -- 等待id=2的锁

-- 事务B
BEGIN;UPDATE account SET balance = balance + 100 WHERE id = 2;  -- 锁住id=2
UPDATE account SET balance = balance - 100 WHERE id = 1;  -- 等待id=1的锁

A等B释放id=2,B等A释放id=1 → 死锁!

MySQL的处理​:检测到死锁后,会选择​回滚其中一个事务​(通常是执行代价较小的那个),并返回错误 Deadlock found when trying to get lock

📚避免死锁的技巧

  1. 按固定顺序访问表/行​:比如总是先更新id=1,再更新id=2
  2. 缩短事务​:尽快提交,减少锁持有时间
  3. 使用低隔离级别​(如读已提交)可减少间隙锁,但可能产生幻读
  4. 合理设计索引​:让UPDATE/DELETE能精确命中行锁,避免升级为表锁
  5. 重试机制​:应用程序捕获死锁错误后,自动重试事务

五、实战:查看当前锁和死锁信息

🎯查看当前正在等待的锁

-- 查看当前事务和锁(MySQL 8.0)
SELECT * FROM performance_schema.data_locks;

-- 查看正在等待的锁
SELECT * FROM performance_schema.data_lock_waits;

🎯查看最近一次死锁信息

SHOW ENGINE INNODB STATUS;

在输出中搜索 LATEST DETECTED DEADLOCK 段落,可以看到造成死锁的SQL。

💡 生产环境定期监控死锁,可以帮助你发现代码中的并发问题。

六、新手必看:3种最常见的“锁升级”陷阱

在使用锁机制时,如果你发现查询变慢了,通常是以下原因导致的“锁升级”:

🚩没走索引的更新:

  1. 错误: UPDATE accounts SET balance = 100 WHERE name = 'John'; (name字段没索引)
  2. 后果: InnoDB找不到具体的行,只能锁住整张表!
  3. 修正: 给 name 加索引,或者确保 WHERE 条件走索引。

🚩间隙锁(Gap Lock)的副作用:

  1. 场景: 可重复读(RR)隔离级别下,为了防止幻读,InnoDB会锁住“索引之间的空隙”。
  2. 后果: 你可能锁住了一段不存在的数据范围,导致别人插不进去。
  3. 修正: 如果并发插入很高,可以考虑将隔离级别降为“读已提交(RC)”。

🚩长事务:

  1. 错误: 一个事务开启后,半天不提交(比如在代码里处理复杂的业务逻辑)。
  2. 后果: 锁一直不释放,后面的请求全堵着。
  3. 修正: “开启事务 -> 执行SQL -> 提交事务”,这三个动作要像闪电一样快!

七、今日学习心得

  1. 锁是并发访问的守门员,保证数据一致性和完整性
  2. InnoDB行锁是并发友好的,但要注意死锁和间隙锁
  3. 死锁不可怕,关键是要捕获并重试,设计好访问顺序

👋 我是数据库小学妹一个用设计师思维学数据库的转行人。我们一起,把复杂的技术变得简单有趣!💕

本文示例基于 ​MySQL​ 8.0,InnoDB 引擎。不同隔离级别下锁的行为有差异,建议查阅官方文档。

相关文章
|
16天前
|
SQL 关系型数据库 MySQL
MySQL慢查询诊断实战:从10秒到0.1秒,我的5步排障法
数据库小学妹分享慢查询优化实战:从10秒降至0.08秒!详解「发现→收集→分析→优化→验证」5步排障法,覆盖慢日志配置、EXPLAIN进阶、索引失效场景、JOIN与分页优化等核心技巧,附真实案例与速查表。
|
2月前
|
SQL 关系型数据库 MySQL
数据量大查询慢?索引让你的SQL秒级响应!|转行学DB第9天
用生活化比喻(如字典目录)详解索引原理:它通过B+树结构加速查询,避免全表扫描;涵盖创建、查看、删除索引方法,联合索引的最左前缀原则,以及读写平衡等实战要点——让查询从“等几秒”变“秒出”!
数据量大查询慢?索引让你的SQL秒级响应!|转行学DB第9天
|
2月前
|
SQL 关系型数据库 MySQL
EXPLAIN 执行计划:一眼看穿你的SQL慢在哪
数据库小学妹带你轻松掌握SQL性能诊断!通过EXPLAIN查看执行计划,精准识别索引失效、全表扫描(ALL)、key为NULL等瓶颈。聚焦type、key、rows等6个关键字段,结合实战案例与避坑指南(如函数滥用、最左前缀破坏),让优化有的放矢。学完即用,告别盲目调优!
|
24天前
|
SQL 算法 中间件
如何让海量数据跑得更快?分库分表实战,从入门到避坑
本文深入解析MySQL分库分表核心原理与实战,结合ShardingSphere中间件,详解垂直/水平拆分策略、路由计算、SQL归并及分布式事务、全局ID、平滑扩容等避坑要点,助你突破单库瓶颈,构建高并发、海量数据下的高可用数据库架构。
|
28天前
|
SQL 关系型数据库 MySQL
间隙锁排查实战:一条SQL揪出阻塞元凶
数据库小学妹带你实战排查间隙锁!用`SHOW ENGINE INNODB STATUS`快速定位`LOCK WAIT`与`gap before rec`,结合`performance_schema.data_lock_waits`精准识别阻塞源,厘清锁等待、死锁根因,避开RC无隙锁、无索引变表锁等常见误区。
|
13天前
|
Prometheus 监控 Cloud Native
MySQL 性能监控实战:从零搭建 Prometheus + Grafana 监控告警体系(附排查 SOP)
数据库小学妹带你从零学监控!本文详解MySQL五大核心指标维度(资源、连接、查询、InnoDB、主从),手把手配置PMM/Prometheus+Grafana监控栈,设置关键告警规则,并提供SQL快照脚本与三步排障SOP。新手友好,即装即用,让性能问题无所遁形!
|
2月前
|
关系型数据库 MySQL 数据库
锁机制避坑指南:3个让DBA头皮发麻的“锁升级”陷阱
本文揭示MySQL InnoDB中行锁意外升级为表锁的三种常见场景:1)WHERE条件无索引导致全表扫描锁;2)外键约束自动加锁子表;3)RR隔离级别下间隙锁扩大范围。针对每种情况提出解决方案:建立索引、评估外键必要性、降低隔离级别等。通过EXPLAIN分析、监控死锁日志可快速定位问题,避免并发性能骤降。掌握这些锁机制特性,能有效提升数据库并发处理能力。
|
14天前
|
SQL 监控 关系型数据库
数据库三大日志深度解析:Redo Log、Binlog、Undo Log 如何守护你的数据
本文由“数据库小学妹”带你厘清MySQL三大核心日志:Redo Log(引擎层物理日志,保障crash-safe)、Undo Log(支撑回滚与MVCC)和Binlog(Server层逻辑日志,用于复制与恢复),详解WAL机制与两阶段提交原理,助你真正理解事务安全底层逻辑。
|
16天前
|
运维 容灾 关系型数据库
数据库容灾配置全攻略:同城容灾vs两地三中心,RPO、RTO一篇讲透
数据库小学妹带你轻松搞懂容灾核心概念!本文用通俗语言解析同城容灾、两地三中心、高可用集群,厘清RPO(数据丢失容忍)与RTO(恢复时效)关键指标,对比方案选型要点,并揭秘同步/异步复制、自动切换、读写分离等实战技术,附避坑指南与演练建议。
|
21天前
|
SQL 监控 druid
数据库连接池避坑指南:告别“连接超时”与“资源耗尽”,让系统跑得更快!
数据库连接池是高并发系统的“隐形地雷”。本文直击5大高频坑点:池大小失当、连接泄露、超时配置错误、空闲连接失效、盲目依赖默认值,并附实战避坑方案、监控技巧与云环境适配建议,助你轻松应对秒杀、大促等流量洪峰,保障系统又快又稳!