业务视角:悲观锁与乐观锁该怎么选?

104 阅读6分钟

业务视角:悲观锁与乐观锁该怎么选?

做业务开发时,你是否遇到过这些问题:秒杀活动库存 “超卖”、用户余额扣成负数、订单状态乱跳?这些本质都是并发资源竞争导致的,而悲观锁和乐观锁,就是解决这类问题的两种核心思路。但很多人搞不清:到底什么业务场景该用悲观锁?什么场景适合乐观锁?今天咱们从业务本质出发,把这个问题讲透。

一、先搞懂:悲观锁与乐观锁的核心区别

在聊场景前,先记住一个核心差异 ——对 “并发” 的信任态度不同

锁类型核心思想通俗理解
悲观锁不信任任何并发,先 “锁死资源” 再操作“先占坑,再做事,谁也别抢”
乐观锁信任并发,先操作再 “校验一致性”“先做事,做完再看有没有人捣乱”

举个生活例子:

  • 悲观锁像你去餐厅吃饭,先占好桌子(锁资源),再叫服务员点餐(操作);
  • 乐观锁像外卖点单,先下单付款(操作),接单后平台校验库存(一致性校验),没库存就退款。

二、什么时候用悲观锁?3 类核心业务场景

悲观锁的优点是强一致性(操作期间资源绝对安全),缺点是性能损耗大(会阻塞其他请求),所以适合 “一致性优先、并发不高” 的场景。

1. 写操作频繁,且涉及核心资产(数据错误代价极高)

典型场景:金融转账、用户余额修改、还款业务

比如银行 “A 转 100 元给 B” 的业务:

  • 流程必须是:查 A 余额≥100 → 扣 A100 → 加 B100
  • 若不锁资源,并发情况下可能出现 “A 余额只剩 50,却被两个请求同时扣 100”,导致余额为负(资损风险)。

这时必须用悲观锁:操作 A 账户时先 “锁住 A 的余额记录”,直到整个转账流程结束才释放锁。哪怕并发量低,也要优先保证资金安全 —— 毕竟金融业务中,“数据正确” 比 “性能快 10ms” 重要 100 倍。

2. 长事务场景(操作耗时久,需持续占用资源)

典型场景:分布式事务、复杂订单确认(需跨系统校验)

比如电商 “下单后扣库存 + 减优惠券 + 冻结积分” 的长事务:

  • 整个流程可能需要调用 3 个系统接口,耗时 1-2 秒;
  • 若用乐观锁,中途可能有其他请求修改库存 / 优惠券,导致最终校验失败,用户反复重试;
  • 用悲观锁锁住 “用户的优惠券记录” 和 “商品库存记录”,直到整个事务完成再释放,能避免中间状态被干扰,减少用户操作失败率。

3. 数据冲突概率极高(不锁就会频繁出错)

典型场景:秒杀中的 “库存预占”(非最终扣减)、票务系统选座

比如高铁票 “选座后 30 分钟未支付” 的场景:

  • 用户选座后,必须锁定该座位(否则 100 人同时选同一个座);
  • 虽然最终支付率可能只有 50%,但 “先锁座再等支付” 是业务必需 —— 总不能让用户选完座,付完钱才发现座位被抢了,体验太差。

三、什么时候用乐观锁?3 类核心业务场景

乐观锁的优点是性能高(不阻塞请求),缺点是可能出现冲突(需处理重试),所以适合 “并发高、一致性要求不极致” 的场景。

1. 读操作频繁,写操作极少(冲突概率低)

典型场景:商品详情页库存展示、用户积分查询、资讯文章点赞

比如电商商品详情页 “剩余 200 件” 的展示:

  • 99% 的请求是用户查看库存(读),只有 1% 是用户下单(写);
  • 若用悲观锁,每次查看库存都要锁记录,会导致页面加载变慢;
  • 用乐观锁:展示时直接读库存,下单时通过 “版本号” 校验(比如库存表加个version字段,下单时判断当前version == 数据库version,一致才扣减),既不影响读性能,又能避免超卖。

2. 高并发场景(秒杀、抢购、限流)

典型场景:双 11 秒杀、直播带货抢购、红包雨

比如 “1 元秒杀 1000 件商品” 的场景:

  • 并发量可能达到 10 万 / 秒,若用悲观锁,大量请求会被阻塞在 “等锁” 环节,导致超时失败,用户体验极差;
  • 用乐观锁:让所有请求先 “预扣库存”(比如用 Redis 计数),然后异步校验一致性,冲突的请求直接返回 “手慢了”,既保证了并发量,又能控制超卖(即使偶尔有 1-2 个超卖,也能通过后续 “订单取消 + 库存回补” 解决,代价远低于悲观锁的性能损耗)。

3. 最终一致性即可(无需实时强一致)

典型场景:社交点赞、评论计数、用户行为统计

比如公众号文章 “10086 个点赞” 的计数:

  • 用户点赞时,不需要实时保证 “每一次点赞都精确到个位数”—— 哪怕偶尔有两个点赞请求冲突,最终统计差 1-2 个,用户也感知不到;
  • 用乐观锁:点赞时携带当前点赞数(比如前端传current_like=100),后端判断 “数据库点赞数 == 100” 就加 1,否则重试 1-2 次,失败就放弃(反正下次刷新会显示正确数),既不影响性能,又能满足业务需求。

四、一张表帮你快速决策:悲观锁 vs 乐观锁

对比维度悲观锁乐观锁
核心适用场景金融转账、长事务、高冲突选座秒杀抢购、读多写少、最终一致场景
并发量低 - 中(高并发会阻塞)高(无阻塞,支持大量请求)
一致性要求强一致性(数据绝对不能错)最终一致性(允许短暂不一致)
业务代价性能损耗(等锁超时)冲突重试(需处理失败逻辑)
实现方式数据库行锁(select ... for update)、分布式锁(Redis/ZooKeeper)版本号(version)、时间戳、CAS 算法

五、业务决策小技巧:3 步选对锁

  1. 先看 “读写比例” :读多写少→乐观锁,写多读少→悲观锁;
  1. 再看 “一致性代价” :数据错误会导致资损(如金融)→悲观锁,偶尔错误可接受(如点赞)→乐观锁;
  1. 最后看 “并发量” :并发量超 1000 / 秒→优先乐观锁,并发量低→悲观锁更简单(不用处理重试)。

总结

悲观锁和乐观锁没有 “谁更好”,只有 “谁更适合”。记住:业务需求决定技术选择—— 当 “安全” 比 “快” 重要时,选悲观锁;当 “快” 比 “绝对安全” 重要时,选乐观锁。实际开发中,也可以结合两者(比如秒杀时用乐观锁预扣,支付时用悲观锁确认),灵活应对复杂业务场景。