我们在聊到后端并发问题,或者说重复下单问题的时候,经常提到"一锁二判三更新".这个"一锁而判三更新",到底是什么呢?本文田螺哥跟大家聊聊哈!
前言
大家好,我是田螺。
我们在聊到后端并发问题,或者说重复下单问题的时候,经常提到"一锁二判三更新".这个"一锁而判三更新",到底是什么呢?本文田螺哥跟大家聊聊哈~~
- 什么是一锁二判三更新
- 为什么需要一锁二判三更新?
- 不同锁策略下的实现差异
1.什么是一锁二判三更新
其实,它是一套处理并发更新数据的标准流程:
- 一锁:表示先获取锁,保证同一时间只有一个操作能执行
- 二判:检查数据状态是否符合预期,防止脏更新
- 三更新:确认无误后执行数据更新操作
比如扣库存的场景,我们来看一个一锁二判三更新的代码例子:
//一锁二判三更新的代码使用例子
@Transactional
public boolean deductStock(Long productId, int quantity) {
// 一锁:获取商品的行锁
// 使用for update进行悲观锁锁定,确保同一时间只有一个事务能操作该商品
Product product = productMapper.selectForUpdateById(productId);
if (product == null) {
throw new RuntimeException("商品不存在");
}
// 二判:判断库存是否充足
if (product.getStock() < quantity) {
throw new RuntimeException("库存不足,当前库存:" + product.getStock());
}
// 三更新:执行库存扣减
int newStock = product.getStock() - quantity;
product.setStock(newStock);
int rows = productMapper.updateById(product);
return rows > 0;
}
对应的 MyBatis update更新方法:
<select id="selectForUpdateById" resultType="com.example.Product">
select * from product where id = #{id}
for update
</select>
2. 为什么需要一锁二判三更新
在并发场景,为什么需要一锁二判三更新这套使用流程呢?
假设类似这种场景:
两个用户同时给同一个商品下单,而商品仅剩最后一件库存。如果没有加锁,可能会出现两个订单都创建成功,但实际库存不足的情况。
同理,也是这个场景,假设你加锁了,如果没有这个二判(判断库存是否充足),依然可能会出现两个订单创建都成功的情况。
错误使用例子:
// 错误示例:无锁无判断
public boolean deductStock(Long productId, int quantity) {
// 1. 查询当前库存
Product product = productMapper.selectById(productId);
// 2. 直接扣减库存(未判断是否充足)
int newStock = product.getStock() - quantity;
product.setStock(newStock);
// 3. 更新库存
return productMapper.updateById(product) > 0;
}
因此,"一锁二判三更新" 正是为这类并发场景设计的解决方案。单独使用锁或单独做判断都无法彻底解决问题,必须三者结合。
3. 不同锁策略下的实现差异
一锁二判三更新中的一锁,其实有不同的实现方式的,既有悲观锁,也有乐观锁。
对于悲观锁,适合写操作比较频繁、冲突概率高的场景:
- 优点:实现简单,冲突处理直接
- 缺点:可能导致锁等待,并发性能较低
比如,我们前面第一小节的就是悲观锁哈实现方式哈
<select id="selectForUpdateById" resultType="com.example.Product">
select * from product where id = #{id}
for update
</select>
如果读操作频繁、写操作冲突概率低的场景,则更适合用乐观锁。简单demo代码如下:
// 乐观锁实现:一锁(版本控制)二判三更新
public boolean deductStock(Long productId, int quantity) {
// 获取当前商品信息(包含版本号)
Product product = productMapper.selectById(productId);
if (product == null) {
throw new RuntimeException("商品不存在");
}
// 二判:判断库存是否充足
if (product.getStock() < quantity) {
throw new RuntimeException("库存不足");
}
// 准备更新数据
int newStock = product.getStock() - quantity;
product.setStock(newStock);
// 版本号+1(乐观锁的关键)
product.setVersion(product.getVersion() + 1);
// 执行更新(WHERE条件包含版本号,相当于一锁的实现)
int rows = productMapper.updateWithVersion(product);
// 如果更新行数为0,说明版本号已变,并发冲突
if (rows == 0) {
throw new RuntimeException("并发更新冲突,请重试");
}
returntrue;
}
很多时候,解决并发问题,我们使用的是Redis分布式锁。
在分布式系统中,"一锁" 通常会升级为分布式锁,而 "二判" 在库存场景下核心就是判断库存是否满足需求。
以 Redis 分布式锁为例,实现分布式环境下的库存扣减简单代码如下:
// 分布式环境下的"一锁二判三更新"
public boolean deductStock(Long productId, int quantity) {
// 分布式锁的key,通常用业务标识+ID
String lockKey = "stock:lock:" + productId;
// 生成唯一标识,用于释放锁时的身份验证
String requestId = UUID.randomUUID().toString();
try {
// 一锁:获取分布式锁(演示用的)
// 第三个参数是超时时间,防止死锁
boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, requestId, 10, TimeUnit.SECONDS);
if (!locked) {
// 获取锁失败,说明有其他进程正在操作,返回失败或重试
returnfalse;
}
// 二判:查询并判断库存
Product product = productMapper.selectById(productId);
if (product == null) {
throw new RuntimeException("商品不存在");
}
if (product.getStock() < quantity) {
throw new RuntimeException("库存不足,当前库存:" + product.getStock());
}
// 三更新:扣减库存
int newStock = product.getStock() - quantity;
product.setStock(newStock);
int rows = productMapper.updateById(product);
return rows > 0;
} finally {
// 释放分布式锁(需要验证身份,防止误删其他进程的锁)
if (requestId.equals(redisTemplate.opsForValue().get(lockKey))) {
redisTemplate.delete(lockKey);
}
}
}
AI大模型学习福利
作为一名热心肠的互联网老兵,我决定把宝贵的AI知识分享给大家。 至于能学习到多少就看你的学习毅力和能力了 。我已将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
一、全套AGI大模型学习路线
AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获取
二、640套AI大模型报告合集
这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获
三、AI大模型经典PDF籍
随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获
四、AI大模型商业化落地方案

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获
作为普通人,入局大模型时代需要持续学习和实践,不断提高自己的技能和认知水平,同时也需要有责任感和伦理意识,为人工智能的健康发展贡献力量
1508

被折叠的 条评论
为什么被折叠?



