先说场景:
物品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).项目分层为