# MySQL 的乐观锁和悲观锁是什么?

6 min read
Table of Contents

MySQL 的乐观锁和悲观锁是什么?

MySQL 乐观锁与悲观锁详解

【核心定义】

乐观锁是一种无锁化的并发控制思想,它假设事务间冲突概率低,只在提交时检测冲突;悲观锁则是一种先加锁后操作的并发控制思想,它假设事务间冲突概率高,在操作前就锁定资源。

【关键要点】

  1. 悲观锁实现方式:通过数据库的排他锁(SELECT ... FOR UPDATE)或共享锁(SELECT ... LOCK IN SHARE MODE)实现,锁定期间其他事务无法修改。
  2. 乐观锁实现方式:通过版本号(version)或时间戳字段实现,更新时检查数据是否被修改,通常结合CAS(Compare And Swap)操作。
  3. 适用场景差异:悲观锁适合写操作频繁、冲突概率高的场景;乐观锁适合读多写少、冲突概率低的场景。

【深度推导/细节】

悲观锁的加锁过程(以InnoDB为例)

-- Step 1: 开启事务并加排他锁
START TRANSACTION;
SELECT * FROM products WHERE id = 1 FOR UPDATE;
-- Step 2: 执行业务逻辑(其他事务的FOR UPDATE会被阻塞)
UPDATE products SET stock = stock - 1 WHERE id = 1;
-- Step 3: 提交事务释放锁
COMMIT;

锁的粒度:InnoDB的行锁是通过对索引项加锁实现的,如果WHERE条件没有用到索引,会升级为表锁。

乐观锁的冲突检测逻辑

-- Step 1: 查询时获取当前版本号
SELECT stock, version FROM products WHERE id = 1;
-- Step 2: 更新时带上版本条件(业务层计算新值)
UPDATE products
SET stock = new_stock, version = version + 1
WHERE id = 1 AND version = old_version;
-- Step 3: 检查影响行数
-- 如果affected_rows = 0,说明版本已变更,需要重试或报错

ABA问题:单纯版本号可能遇到值回滚问题,可通过时间戳或递增版本号解决。

【关联/对比】

维度悲观锁乐观锁
并发性能低(串行执行)高(并行执行)
死锁风险高(可能形成等待环)无(无锁机制)
实现复杂度低(数据库原生支持)高(需业务层处理冲突)
数据一致性强(锁定期间绝对一致)最终一致(可能需重试)
适用场景库存扣减、金额修改点赞计数、状态更新

与MVCC的关系:InnoDB的MVCC(多版本并发控制)本质是乐观锁思想在数据库引擎层的实现,通过Read View和undo log实现非锁定读。

【线程安全考量】

  1. 悲观锁的线程安全:数据库层面保证,但需要正确管理事务边界,避免长事务导致锁等待超时。
  2. 乐观锁的线程安全:依赖业务层重试机制,常见方案:
    • 有限次重试(3-5次)
    • 指数退避策略
    • 进入消息队列异步处理

【版本差异与实践优化】

  • MySQL 5.7+:支持SKIP LOCKED和NOWAIT语法,优化悲观锁的等待机制
  • MySQL 8.0:原子DDL和更好的死锁检测
  • 优化建议:
    • 混合使用:关键业务用悲观锁,非关键业务用乐观锁
    • 监控指标:锁等待时间、死锁频率、重试次数
    • 索引优化:确保WHERE条件使用索引,避免锁升级

『面试官追问』

  1. 乐观锁在超高并发下大量失败重试怎么办?

    • 引入令牌桶或漏桶限流
    • 将冲突操作序列化到消息队列
    • 考虑改用悲观锁或分布式锁
  2. SELECT FOR UPDATE会锁表还是锁行?

    • 取决于WHERE条件是否使用索引
    • 使用主键/唯一索引:锁行
    • 无索引或索引失效:锁表
    • 间隙锁:防止幻读,锁住范围间隙
  3. 乐观锁的版本号字段用什么类型?

    • 推荐BIGINT自增,避免溢出
    • 时间戳精度不够(毫秒级可能重复)
    • 可结合业务流水号作为版本标识
  4. 如何选择两种锁机制?

    • 冲突频率 > 20%:悲观锁
    • 响应时间要求高:乐观锁
    • 数据热点严重:考虑分库分表+乐观锁
  5. 乐观锁与CAS的关系?

    • 乐观锁是思想,CAS是实现方式之一
    • 数据库乐观锁通过WHERE条件实现CAS语义
    • Java中的Atomic类使用CPU指令级CAS

总结要点:悲观锁“先防后做”,乐观锁“先做后验”;选择依据是冲突概率和性能要求;实际生产常根据业务场景混合使用,并配合监控告警体系。

My avatar

文章看完了,不打算去别的篇章转转吗?👀 感谢你的耐心阅读!如果你有问题想探讨,或者发现了文中的 Bug,请务必通过页脚的链接联系我


More Posts

# MySQL 的索引下推是什么?

7 min read

索引下推(Index Condition Pushdown,ICP)是 MySQL 5.6 引入的一项查询优化技术,其本质是将 WHERE 子句中部分过滤条件下推到存储引擎层执行,减少回表次数和服务器层的数据处理量。

Read

Comments