乐观锁、悲观锁和分布式锁,你用对了吗?

乐观锁、悲观锁和分布式锁的使用

后台开发最怕什么?数据被改乱。 把数据库想成公共厨房,锅就是数据。 三个人同时炒菜,锅翻了,菜就糊了。 锁就是排队机制,让锅一次只给一个人用。

下面讲讲我们3种最常用的锁:乐观锁、悲观锁、分布式锁。

1. 乐观锁

使用场景

适合冲突少的场景。比如用户修改自己的资料、库存更新不频繁的情况。

实际案例

我们有个商品表,结构大概是这样的:

sql 复制代码
CREATE TABLE product (
  id INT PRIMARY KEY,
  name VARCHAR(50),
  stock INT,
  version INT DEFAULT 0
);

注意那个version字段,这就是乐观锁的关键。

当用户下单时,我们会这样更新库存:

sql 复制代码
UPDATE product 
SET stock = stock - 1, version = version + 1 
WHERE id = 1001 AND version = 2;

只有当当前版本是2的时候,才允许扣减库存,并把版本号加1。

如果两个请求同时来,第一个执行完后版本变成3,第二个请求因为version=2不成立,更新就会失败。这时候程序就知道:"哦,有人抢先改了,我得重新查一下库存再处理。"

小结

  • 优点:性能好,不阻塞
  • 缺点:冲突多了会反复重试
  • 适合:读多写少、并发不高的场景

2. 悲观锁:先上锁,再操作

使用场景

适合冲突频繁的场景。比如秒杀、抢票这种大家一窝蜂涌进来的情况。

实际案例

还是上面那个商品表,但这次我们用悲观锁:

sql 复制代码
BEGIN;

-- 先锁定这条记录,别人不能动
SELECT * FROM product WHERE id = 1001 FOR UPDATE;

-- 查到库存是5,减1
UPDATE product SET stock = 4 WHERE id = 1001;

COMMIT;

FOR UPDATE这个语句很关键,它会把这行数据锁住,直到事务结束。其他人想执行同样的查询,就得排队等着。

这样就能保证同一时间只有一个请求能修改库存,彻底避免超卖。

小结

  • 优点:简单直接,不会超卖
  • 缺点:性能差,容易阻塞
  • 适合:高并发、强一致性的场景

3. 分布式锁:跨机器的协调

使用场景

当你有多个服务实例(比如部署了3台服务器),单机锁不管用了,就得用分布式锁。

实际案例

我们系统做了集群,3台服务器一起处理订单。这时候用数据库锁或synchronized都没用------锁不住别的机器上的进程。

我们用了 Redis 来实现分布式锁:

java 复制代码
// 伪代码
String lockKey = "lock:product_1001";

// 尝试加锁,3秒自动过期
Boolean locked = redis.set(lockKey, "1", "NX", "EX", 3);

if (locked) {
    try {
        // 执行扣库存逻辑
        deductStock(1001);
    } finally {
        // 释放锁
        redis.del(lockKey);
    }
} else {
    // 加锁失败,说明别人正在处理
    System.out.println("商品太火爆,再试一次!");
}

这里用到了 Redis 的 SET key value NX EX 命令:

  • NX:只有key不存在时才设置
  • EX:3秒后自动过期(防止程序崩溃导致锁永远不释放)

小结

  • 优点:能跨服务协调
  • 缺点:依赖Redis,实现要小心死锁
  • 适合:分布式系统、集群环境

什么时候用哪种锁?

我总结了个简单判断方法:

场景 推荐用锁
单机应用,偶尔更新 乐观锁
单机应用,高频修改 悲观锁
多台服务器部署 分布式锁
读多写少 乐观锁
写操作特别频繁 悲观锁 or 分布式锁

最后一点心得

锁不是越多越好,而是够用就好。 先想清楚"锅会不会翻",再决定"怎么排队"。 技术就是解决问题的工具!用顺手了,也就没那么可怕了。

本文首发于微信公众号「刘大华的开发笔记」我是大华,专注分享前后端开发的实战笔记。 关注我,少走弯路,一起进步!

相关推荐
李慕婉学姐20 小时前
【开题答辩过程】以《基于JAVA的校园即时配送系统的设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
java·开发语言·数据库
奋进的芋圆21 小时前
Java 延时任务实现方案详解(适用于 Spring Boot 3)
java·spring boot·redis·rabbitmq
sxlishaobin21 小时前
设计模式之桥接模式
java·设计模式·桥接模式
model200521 小时前
alibaba linux3 系统盘网站迁移数据盘
java·服务器·前端
荒诞硬汉1 天前
JavaBean相关补充
java·开发语言
提笔忘字的帝国1 天前
【教程】macOS 如何完全卸载 Java 开发环境
java·开发语言·macos
2501_941882481 天前
从灰度发布到流量切分的互联网工程语法控制与多语言实现实践思路随笔分享
java·开发语言
華勳全栈1 天前
两天开发完成智能体平台
java·spring·go
alonewolf_991 天前
Spring MVC重点功能底层源码深度解析
java·spring·mvc
沛沛老爹1 天前
Java泛型擦除:原理、实践与应对策略
java·开发语言·人工智能·企业开发·发展趋势·技术原理