浅谈库存扣减和锁

本文探讨了在并发环境下如何确保库存扣减的正确性,通过分析不同锁策略,包括synchronized、直接更新、CAS、数据库锁和分布式锁。强调了每个方案的优缺点,如synchronized在分布式环境中的局限,直接更新的不可通用性,CAS的ABA问题,数据库锁的死锁风险以及分布式锁的跨JVM适用性。
摘要由CSDN通过智能技术生成
                先说场景:

物品W现在库存剩余1个,  用户P1,P2同时购买.则只有1人能购买成功.(前提是不允许超卖)

秒杀也是类似的情况, 只有1件商品,N个用户同时抢购,只有1人能抢到..

这里不谈秒杀设计,不谈使用队列等使请求串行化,就谈下怎么用锁来保证数据正确.


常见的实现方案有以下几种:

1.代码同步, 例如使用 synchronized ,lock 等同步方法

2.不查询,直接更新  update table set surplus = (surplus - buyQuantity) where id = xx and (surplus - buyQuantity) > 0

3.使用CAS, update table set surplus = aa where id = xx and version = y

4.使用数据库锁, select xx for update

5.使用分布式锁(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); // 记录日志... // 其他业务...}


在方法声明加上synchronized关键字,实现同步,这样2个用户同时购买,到buy方法时候同步执行,第2个用户执行的时候,会库存不足.

嗯.. 看着挺合理的,以前我也是这么干的偷笑. 所以现在碰到别人这样回答,我就会在心里默默的想.小伙子你是没踩过这坑啊.


先说下这个方案的前提配置:

1).使用spring 声明式事务管理

2).事务传播机制使用默认的(PROPAGATION_REQUIRED)

3).项目分层为controller-service-dao 3层, 事务管理在service层


这个方案不可行,主要是因为以下几点:

1).synchronized 作用范围是单个jvm实例, 如果做了集群,分布式等,就没用了

2).synchronized是作用在对象实例上的,如果不是单例,则多个实例间不会同步(这个一般用spring管理bean,默认就是单例)

3).单个jvm时,synchronized也不能保证多个数据库事务的隔离性. 这与代码中的事务传播级别,数据库的事务隔离级别,加锁时机等相关.

3-1).先说隔离级别,常用的是 Read Committed 和 Repeatable Read ,另外2种不常用就不说了

3-1-1)RR(Repeatable Read)级别.mysql默认的是RR,事务开启后,不

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值