MySQL 乐观锁与悲观锁怎么实现?

在数据库并发控制中,乐观锁和悲观锁是两种核心的并发控制策略,它们分别适用于不同的业务场景。本文将详细介绍这两种锁机制在MySQL中的实现方式、适用场景以及实际应用案例。

一、悲观锁:先加锁再操作

1. 核心思想

悲观锁认为并发冲突随时可能发生,因此在访问数据前先对数据加锁,阻止其他事务修改数据,直到当前事务完成操作后才释放锁。

2. 实现方式

在MySQL中,悲观锁主要通过以下两种语句实现:

排他锁(Exclusive Lock)

START TRANSACTION;
SELECT * FROM products WHERE id = 1 FOR UPDATE;
-- 执行业务逻辑
UPDATE products SET stock = stock - 1 WHERE id = 1;
COMMIT;

共享锁(Shared Lock)

START TRANSACTION;
SELECT * FROM products WHERE id = 1 LOCK IN SHARE MODE;
-- 其他事务可以读取但不能修改
COMMIT;

3. 关键特性

  • 锁粒度:InnoDB引擎默认使用行级锁,基于索引实现精准锁定
  • 锁释放时机:事务结束时(提交或回滚)自动释放锁
  • 事务要求:必须在显式事务中使用,否则锁会立即释放

4. 注意事项

  • 必须关闭MySQL的自动提交:SET autocommit = 0;
  • 使用索引条件,避免无索引导致表级锁
  • 控制事务执行时间,避免长时间持有锁引发死锁

二、乐观锁:先操作再校验

1. 核心思想

乐观锁假设并发冲突很少发生,因此在读取数据时不加锁,只在更新数据时检查数据是否被其他事务修改过。如果数据未被修改,则更新成功;否则更新失败,需要重试或提示用户。

2. 实现方式

版本号机制(最常用)

-- 创建表时添加version字段
CREATE TABLE products (
    id INT PRIMARY KEY,
    name VARCHAR(100),
    stock INT,
    version INT DEFAULT 0
);

-- 更新数据时检查版本号
UPDATE products 
SET stock = stock - 1, version = version + 1 
WHERE id = 1 AND version = 2;

时间戳机制

-- 创建表时添加时间戳字段
CREATE TABLE products (
    id INT PRIMARY KEY,
    name VARCHAR(100),
    stock INT,
    update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- 更新数据时检查时间戳
UPDATE products 
SET stock = stock - 1, update_time = NOW() 
WHERE id = 1 AND update_time = '2025-01-06 10:00:00';

3. 冲突处理

  • 通过ROW_COUNT()判断更新是否成功
  • 更新失败时,可以重试或提示用户数据已被修改
  • 建议在应用层实现重试机制

三、两种锁机制对比

维度悲观锁乐观锁
核心思想先加锁再操作先操作再校验
实现方式SELECT … FOR UPDATE版本号/时间戳机制
性能开销高(锁竞争、阻塞)低(无锁等待)
数据一致性强一致性最终一致性
适用场景高冲突、写多读少低冲突、读多写少
典型应用金融转账、库存扣减商品浏览、评论系统

四、实际应用场景选择

1. 选择悲观锁的场景

  • 金融业务:银行转账、账户余额修改,数据一致性要求极高
  • 库存扣减:秒杀系统、商品抢购,避免超卖
  • 长事务场景:操作耗时久,需要持续占用资源

2. 选择乐观锁的场景

  • 社交应用:用户信息更新、评论发布
  • 内容管理系统:文章编辑、点赞功能
  • 高并发读场景:商品浏览、新闻阅读

五、最佳实践建议

1. 悲观锁优化

  • 按固定顺序加锁,避免死锁
  • 使用索引条件,确保行级锁
  • 控制事务粒度,减少锁持有时间

2. 乐观锁优化

  • 添加重试机制,处理更新失败
  • 使用INT类型版本号,避免溢出
  • 高并发场景可结合CAS操作

3. 混合使用策略

在实际业务中,可以根据不同场景灵活选择:

  • 核心业务使用悲观锁保证强一致性
  • 非核心业务使用乐观锁提升并发性能
  • 必要时可结合分布式锁解决跨系统并发问题

总结

MySQL的乐观锁和悲观锁各有优劣,选择哪种锁机制取决于具体的业务场景和性能要求。悲观锁通过数据库层面的锁机制保证强一致性,适合高冲突场景;乐观锁通过业务逻辑实现并发控制,适合低冲突、高并发场景。在实际开发中,应根据业务特点合理选择,必要时可以混合使用,以达到最佳的性能和一致性平衡。


作 者:南烛
链 接:https://www.itnotes.top/archives/1138
来 源:IT笔记
文章版权归作者所有,转载请注明出处!


上一篇
下一篇