MySQL锁机制:悲观锁VS乐观锁详解
以下是MySQL悲观锁与乐观锁的详细解析:
一、核心概念对比
特性 | 悲观锁 | 乐观锁 |
---|---|---|
加锁时机 | 操作前加锁 | 提交时检查冲突 |
实现原理 | 数据库原生锁机制 | 版本号/时间戳校验 |
并发性能 | 高冲突场景稳定 | 低冲突场景高效 |
典型应用 | 库存扣减、支付交易 | 评论计数、配置更新 |
二、悲观锁实现细节
-
InnoDB锁类型
- 排他锁(X锁):
SELECT ... FOR UPDATE
锁定记录,阻塞其他写操作 - 共享锁(S锁):
LOCK IN SHARE MODE
允许多读但禁止写 - 间隙锁:防止幻读,锁定索引记录间隙
- 排他锁(X锁):
-
使用示例
START TRANSACTION; SELECT stock FROM products WHERE id=1001 FOR UPDATE; -- 锁定行 UPDATE products SET stock=stock-1 WHERE id=1001; -- 保证原子性 COMMIT;
需确保操作在事务中且命中索引,否则退化为表锁
三、乐观锁实现方案
-
版本号机制
-- 建表时增加version字段 UPDATE products SET name='新品', version=version+1 WHERE id=1 AND version=5; -- 版本校验
返回受影响行数为0时需重试
-
时间戳方案
UPDATE orders SET status='paid', last_modified=NOW() WHERE id=100 AND last_modified='2025-08-16 10:00:00';
四、选型决策树
五、性能优化建议
- 悲观锁避免长事务,锁定后尽快提交
- 乐观锁需设置重试次数上限(如3次)
- 混合使用:热点数据用悲观锁,非热点用乐观锁
六、特殊场景处理
- 乐观锁ABA问题:追加时间戳或业务流水号校验
- 悲观锁死锁:通过
SHOW ENGINE INNODB STATUS
分析死锁链
两种锁机制本质是并发控制时空观的差异:悲观锁以空间换时间(提前锁定),乐观锁以时间换空间(事后校验)。实际开发中应根据业务特征选择,金融交易类推荐悲观锁,社交feed流更适合乐观锁。