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

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

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

下面讲讲我们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 分布式锁

最后一点心得

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

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

相关推荐
前端工作日常27 分钟前
我学习到的Java中domain和dto区别
java·后端
码农学院1 小时前
基于Spring Boot的跨境电商多语言订单管理系统架构设计
java·大数据·spring boot
技术小结-李爽2 小时前
【工具】pom文件的<packaging>
java·maven
l156469482 小时前
突围!图文混合知识库难以解析,Kimi-K3 原生视觉架构深耕知识工作,DMXAPI 统一接口,缩短项目开发周期
java·大数据·开发语言
布吉岛的石头3 小时前
Java 程序员第 45 阶段11:网关统一路由大模型接口,配合 Nacos 配置治理,灰度路由:基于Nacos元数据实现大模型服务灰度发布与权重路由
java·服务发现
我命由我123453 小时前
Android 开发问题:Cannot resolve method ‘repeat‘ in ‘String‘
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
baozhengw4 小时前
信创改造-SpringBootJar包改为WAR包部署Tomcat
java·tomcat
M1A14 小时前
基于 Spring AOP 构建系统操作日志:从注解设计到异步落库的完整实战
java
RainCity4 小时前
Java Swing 自定义组件库分享(十五)
java·笔记·后端
farerboy4 小时前
23-Java 构造函数
java·后端