news 2026/7/6 11:14:01

MySQL 中的锁你真的了解吗?从行锁到死锁,一篇彻底讲透!

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MySQL 中的锁你真的了解吗?从行锁到死锁,一篇彻底讲透!

视频看了几百小时还迷糊?关注我,几分钟让你秒懂!


在 Spring Boot 项目中,你是否遇到过这些问题:

  • 用户下单时,库存扣成负数?
  • 两个线程同时修改同一条记录,结果数据错乱?
  • 程序突然卡住,日志显示“等待锁”?

这些问题的背后,往往都是MySQL 锁机制没搞清楚!

今天我们就用Java + Spring Boot + MySQL(InnoDB),手把手带你搞懂:

  • MySQL 到底有哪些锁?
  • 什么情况下会加锁?
  • 如何避免死锁?
  • 如何用代码正确处理并发?

一、为什么需要锁?—— 并发场景下的数据一致性

📌 场景:电商扣库存

// 伪代码 public void reduceStock(Long productId) { Product product = productMapper.selectById(productId); if (product.getStock() > 0) { product.setStock(product.getStock() - 1); productMapper.updateById(product); // 危险! } }

问题
如果两个用户同时下单,都读到stock=1,然后各自减 1 → 最终stock=-1

✅ 解决方案:加锁,确保“读-判断-写”是原子操作。

而 MySQL 的锁,就是实现这种原子性的底层保障。


二、MySQL 锁的分类(InnoDB 引擎)

InnoDB 支持行级锁,这是它比 MyISAM(只支持表锁)更适合高并发的关键!

🔒 1. 按粒度分

类型说明并发性
表锁(Table Lock)锁整张表(MyISAM 默认)❌ 差
行锁(Row Lock)只锁特定行(InnoDB 默认)✅ 高
间隙锁(Gap Lock)锁索引之间的“间隙”防幻读
临键锁(Next-Key Lock)行锁 + 间隙锁InnoDB 默认

💡 InnoDB 在RC(Read Committed)RR(Repeatable Read)隔离级别下,锁行为不同!


🔒 2. 按类型分

锁类型作用典型场景
共享锁(S Lock)允许多个事务读同一行SELECT ... LOCK IN SHARE MODE(已废弃)
排他锁(X Lock)禁止其他事务读写UPDATE / DELETE / SELECT ... FOR UPDATE
意向锁(Intention Lock)表级锁,表示“想对某行加锁”自动加,无需关心

重点掌握:排他锁(X Lock)和间隙锁!


三、实战:Spring Boot 中如何触发 MySQL 行锁?

场景:安全扣库存

✅ 正确做法:使用SELECT ... FOR UPDATE
@Service @Transactional public class OrderService { @Autowired private ProductMapper productMapper; public boolean createOrder(Long userId, Long productId) { // 1. 加排他锁查询库存 Product product = productMapper.selectForUpdate(productId); if (product == null || product.getStock() <= 0) { throw new RuntimeException("库存不足"); } // 2. 扣库存(此时别人无法修改这行) product.setStock(product.getStock() - 1); productMapper.updateById(product); // 3. 创建订单... return true; } }

对应的 Mapper:

@Mapper public interface ProductMapper extends BaseMapper<Product> { @Select("SELECT * FROM product WHERE id = #{id} FOR UPDATE") Product selectForUpdate(@Param("id") Long id); }

🔑 关键:FOR UPDATE会在查询的行上加排他锁(X Lock),直到事务提交才释放。


四、不同隔离级别下的锁行为(重点!)

MySQL 默认隔离级别是RR(Repeatable Read),但很多公司用RC(Read Committed)

隔离级别SELECT ... FOR UPDATE是否加间隙锁?幻读风险
RC(读已提交)❌ 不加间隙锁,只锁具体行✅ 有幻读
RR(可重复读)✅ 加临键锁(行+间隙)❌ 无幻读

🌰 举例:防止“幻读”

user(id PK, name),当前有 id=1,3,5

执行:

SELECT * FROM user WHERE id > 2 AND id < 6 FOR UPDATE;
  • 在 RR 下:不仅锁住 id=3,5,还锁住 (2,3)、(3,5)、(5,+∞) 的间隙,防止别人插入 id=4!
  • 在 RC 下:只锁 id=3,5,别人仍可插入 id=4 → 出现幻读。

💡 如果你用的是RC + 唯一索引等值查询,InnoDB 会退化为记录锁,不加间隙锁。


五、死锁(Deadlock)是怎么发生的?

📌 经典死锁场景

时间事务 A事务 B
T1UPDATE product SET stock=stock-1 WHERE id=1;
T2UPDATE product SET stock=stock-1 WHERE id=2;
T3UPDATE product SET stock=stock-1 WHERE id=2;(等待 B 释放)
T4UPDATE product SET stock=stock-1 WHERE id=1;(等待 A 释放)

💥 结果:互相等待,死锁!

MySQL 会自动检测死锁,并回滚其中一个事务(通常是 undo log 少的那个)。

🔍 如何查看死锁日志?

SHOW ENGINE INNODB STATUS;

LATEST DETECTED DEADLOCK部分能看到详细信息。


六、如何避免死锁?(开发建议)

✅ 1.按固定顺序访问资源

  • 总是先锁 id 小的,再锁 id 大的
  • 避免交叉加锁

✅ 2.减少事务持有锁的时间

  • 事务尽量短
  • 不要在事务中做 RPC 调用、sleep 等耗时操作

✅ 3.加锁前先排序

// 错误:随机顺序 List<Long> ids = Arrays.asList(3L, 1L, 2L); // 正确:先排序 ids.sort(Long::compareTo); for (Long id : ids) { productMapper.selectForUpdate(id); // 按顺序加锁 }

✅ 4.设置超时时间

# application.yml spring: datasource: hikari: connection-timeout: 3000 # 或在 SQL 中

或在 MySQL 层设置:

SET innodb_lock_wait_timeout = 10; -- 等待锁超时 10 秒

七、反例 vs 正例对比

❌ 反例:无锁扣库存(高并发必出错)

// 危险!没有加锁 Product p = productMapper.selectById(1001); if (p.getStock() > 0) { p.setStock(p.getStock() - 1); productMapper.updateById(p); }

✅ 正例:FOR UPDATE+ 事务

@Transactional public void safeReduceStock(Long productId) { Product p = productMapper.selectForUpdate(productId); if (p.getStock() <= 0) throw new RuntimeException("无库存"); p.setStock(p.getStock() - 1); productMapper.updateById(p); }

八、高级技巧:乐观锁 vs 悲观锁

方案原理适用场景
悲观锁(FOR UPDATE先加锁,再操作写多读少,冲突频繁
乐观锁(version 字段)更新时检查 version读多写少,冲突少

乐观锁示例:

ALTER TABLE product ADD COLUMN version INT DEFAULT 0;
// 更新时带 version 条件 int rows = productMapper.updateByVersion( productId, newStock, oldVersion ); if (rows == 0) { throw new RuntimeException("并发修改,请重试"); }

💡建议

  • 库存、余额等强一致性场景 → 用悲观锁
  • 商品信息、点赞数等 → 用乐观锁

九、总结:MySQL 锁核心要点

问题答案
InnoDB 默认锁粒度?行锁
UPDATE会加什么锁?排他锁(X Lock)
RR 隔离级别会加间隙锁吗?会!(防幻读)
如何避免死锁?固定顺序 + 短事务 + 超时
高并发扣库存用什么锁?SELECT ... FOR UPDATE(悲观锁)

记住:锁是双刃剑——不用会数据错乱,滥用会性能下降甚至死锁!


视频看了几百小时还迷糊?关注我,几分钟让你秒懂!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/24 13:37:03

西门子 S7 - 200 SMART 与台达变频器 485 通讯实现触摸屏控制

西门子s7 200smart与台达变频器485通讯 目标&#xff1a;用触摸屏和西门子smart 控制变频器通讯 器件&#xff1a;西门子s7 200 smart PLC&#xff0c;台达VFD-M变频器&#xff0c;昆仑通态触摸屏(带以太网)&#xff0c;中途可以加路由器 控制方式&#xff1a;触摸屏与plc以太网…

作者头像 李华
网站建设 2026/7/5 8:54:11

Cesium中的 Entity、Terrain、DataSource开发场景示例

&#x1f3af; 一、Entity模块&#xff1a;SampledPositionProperty 深度解析与动态航线实现 1. SampledPositionProperty 核心定义与用途 &#x1f50d; 定义 SampledPositionProperty 是 Cesium 中用于描述随时间变化的三维位置属性的核心类&#xff0c;支持通过采样点插值…

作者头像 李华
网站建设 2026/7/1 1:15:23

低成本拿捏高级感|国潮礼盒 AI 渲染工具,年货节设计神器

每年的春节年货节都让国潮礼盒的设计需求不断增加。作为一名物料设计师&#xff0c;我经常需要在繁忙的设计过程中应对快速的市场变化&#xff0c;尤其是在节庆礼盒设计的时效性和独特性上。在传统设计工具下&#xff0c;设计周期长、迭代慢&#xff0c;总是让人感到压力山大。…

作者头像 李华
网站建设 2026/7/1 18:40:18

2026 AI市场分析榜单发布!原圈科技领衔四大平台破解增长焦虑

在2026年的AI市场分析领域,原圈科技被普遍视为值得关注的佼佼者。本文深入盘点四大主流平台,对比分析其在应对数据孤岛、赋能营销战略上的优劣。其中,原圈科技以其"天眼全域洞察平台"展现了从数据整合到智能策略生成的全链路能力,在技术原创性、数据处理深度等多个维…

作者头像 李华
网站建设 2026/7/3 18:05:06

VisIC的两条增长曲线:D3GaN瞄准电车主驱与AI供电

作者&#xff1a;毛烁在功率半导体的发展图谱中&#xff0c;2026年是一个关键的转折点。行业为碳化硅&#xff08;SiC&#xff09;在800V高压平台上的产能扩充而焦虑时&#xff0c;另一条技术路线正在悄然完成从“理论可行”到“量产落地”的一跃。2026年1月&#xff0c;全球汽…

作者头像 李华
网站建设 2026/6/22 16:59:45

救命神器!MBA必看!8款AI论文写作软件深度测评与推荐

救命神器&#xff01;MBA必看&#xff01;8款AI论文写作软件深度测评与推荐 2026年MBA必备的AI论文写作工具测评 在当前快节奏的学术环境中&#xff0c;MBA学生和研究者面临着越来越多的写作挑战。从选题构思到文献综述&#xff0c;再到数据分析与结论撰写&#xff0c;每一个环…

作者头像 李华