MySQL悲观锁实现:面试高频考点深度剖析
🔵2025年Java面试宝典:
链接: https://pan.baidu.com/s/1RUVf75gmDVsg8MQp4yRChg?pwd=9b3g 提取码: 9b3g
什么是悲观锁?
简单说,悲观锁就是“先防后做”——默认并发操作会冲突,访问数据前先加锁。在MySQL中,悲观锁主要依赖数据库自身的锁机制(如行锁、表锁)实现。举个例子:电商扣库存时,直接锁住商品记录,确保当前事务完成前其他事务无法修改。
MySQL悲观锁的实现方式
核心就一招:SELECT ... FOR UPDATE。
在事务中执行该语句,MySQL会对查询结果集加排他锁(X锁),其他事务无法修改或加共享锁,直到当前事务提交或回滚。
使用步骤
- 开启事务:
BEGIN; - 加悲观锁查询:
SELECT * FROM products WHERE id = 1001 FOR UPDATE; -- 锁住id=1001的行 - 执行业务逻辑(如扣减库存):
UPDATE products SET stock = stock - 1 WHERE id = 1001; - 提交事务:
COMMIT;(释放锁)
💡关键点:
FOR UPDATE必须配合事务使用,否则锁立即释放- 锁的粒度取决于查询条件(走索引锁行,否则可能锁表)
- 超时机制:
innodb_lock_wait_timeout控制等待锁的时间(默认50秒)
悲观锁的适用场景
- 写多读少:比如秒杀库存扣减
- 强一致性要求:如账户余额操作
- 业务逻辑复杂:需连续操作同一数据的多个步骤
举个栗子🌰
面试官问:“如何防止超卖?” 你可以答:
“用
SELECT ... FOR UPDATE锁住商品行,在事务内校验库存并扣减。比如:BEGIN; SELECT stock FROM items WHERE id=123 FOR UPDATE; -- 检查stock>0后执行UPDATE UPDATE items SET stock=stock-1 WHERE id=123; COMMIT;
悲观锁的坑点避雷
- 死锁风险:多个事务互相等待锁,需设计合理的锁顺序
- 性能瓶颈:高并发时大量线程阻塞,超时错误飙升
- 锁升级:行锁可能升级为表锁(如全表扫描时)
✅ 优化建议:
- 尽量通过索引精确锁定数据范围
- 事务操作保持轻量,避免锁持有时间过长
- 若业务允许,用乐观锁(版本号)替代
面试实战技巧
当面试官问“悲观锁和乐观锁区别?”时,快速对比:
| 维度 | 悲观锁 | 乐观锁 |
|----------------|--------------------------|----------------------|
| 实现原理 | 先加锁再操作 | 冲突检测+重试 |
| 适用场景 | 写多读少、强一致性 | 读多写少、容忍重试 |
| 数据库支持 | SELECT FOR UPDATE | 版本号/时间戳字段 |
| 性能影响 | 并发高时阻塞严重 | 并发冲突少时性能更佳 |
🎁 会员福利提示
如果你需要购买面试鸭会员,通过 面试鸭返利网 找我,可额外返利25元!海量大厂真题+详解,锁定核心考点不迷路→
总结一句话
悲观锁是事务安全的“守门员”,FOR UPDATE一出手,数据竞争绕道走。搞清锁粒度、事务边界和场景适配,面试直接拿捏!
📌 锁机制示意图:
(图示:事务A持有行锁时,事务B的修改操作被阻塞)
更多面试硬核干货→ 面试鸭题库





