库存扣减和锁
常见的实现方案:
- 代码同步, 例如使用 synchronized ,lock 等同步方法
- 不查询,直接更新
update table set surplus = (surplus - buyQuantity) where id = xx and (surplus - buyQuantity) > 0
- 使用CAS,
update table set surplus = aa where id = xx and version = y
- 使用数据库锁,
select xx for update
- 使用分布式锁(zookeeper,redis等)
1.代码同步, 使用 synchronized ,lock 等同步方法
public synchronized void buy(String productName, Integer buyQuantity) {
// 其他校验...
// 校验剩余数量
Product product = 从数据库查询出记录;
if (product.getSurplus < buyQuantity) {
return "库存不足";
}
// set新的剩余数量
product.setSurplus(product.getSurplus() - quantity);
// 更新数据库
update(product);
// 记录日志...
// 其他业务...
}
先说下这个方案的前提配置:
- 使用spring 声明式事务管理
- 事务传播机制使用默认的(PROPAGATION_REQUIRED)
- 项目分层为controller-service-dao 3层, 事务管理在service层
这个方案不可行,主要是因为以下几点:
1).synchronized 作用范围是单个jvm实例, 如果做了集群,分布式等,就没用了
2).synchronized是作用在对象实例上的,如果不是单例,则多个实例间不会同步(这个一般用spring管理bean,默认就是单例)
3).单个jvm时,synchronized也不能保证多个数据库事务的隔离性. 这与代码中的事务传播级别,数据库的事务隔离级别,加锁时机等相关.
2.不查询,直接更新
public synchronized void buy(String productName, Integer buyQuantity) {
// 其他校验...
int 影响行数 = update table set surplus = (surplus - buyQuantity) where id = 1 and (surplus - buyQuantity) > 0 ;
if (result < 0) {
return "库存不足";
}
// 记录日志...
// 其他业务...
}
这样确实可以实现,不过有一些其他问题:
- 不具备通用性,例如add操作
- 库存操作一般要记录操作前后的数量等,这样没法记录
- 其他...
3.使用CAS, update table set surplus = aa where id = xx and yy = y
public void buy(String productName, Integer buyQuantity) {
// 其他校验...
Product product = getByDB(productName);
int 影响行数 = update table set surplus = (surplus - buyQuantity) where id = 1 and surplus = 查询的剩余数量 ;
while (result == 0) {
product = getByDB(productName);
if (查询的剩余数量 > buyQuantity) {
影响行数 = update table set surplus = (surplus - buyQuantity) where id = 1 and surplus = 查询的剩余数量 ;
} else {
return "库存不足";
}
}
// 记录日志...
// 其他业务...
}
4.使用数据库锁, select xx for update
public void buy(String productName, Integer buyQuantity) {
// 其他校验...
Product product = select * from table where name = productName for update;
if (查询的剩余数量 > buyQuantity) {
影响行数 = update table set surplus = (surplus - buyQuantity) where name = productName ;
} else {
return "库存不足";
}
// 记录日志...
// 其他业务...
}
5.使用分布式锁(zookeeper,redis等)
分布式锁的实现方案有很多:基于redis,基于zookeeper,基于数据库等等
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战