大家都知道在一个项目当中,当商品库存出现高并发的时候出现超卖的问题,我们该如何解决呢?
在一个高并发的业务当中,比如我们的一元秒杀业务。
那么首先我们的逻辑需要先列出来,我们防止商品超卖的时候,还要保证一个用户只能秒杀一单
那么要考虑的有那些呢?
1、是否还有库存
2、用户是否购买过
3、加锁的位置以及实现
那么我们就可以已以下的案例来看,现在假设有一个商城有10张优惠券,并且每人只能购买一张。我们该如何实现呢?
@Service
public class OrderServiceImpl implements OrderService{
@AutoWired
private ShopService shopService;
/**
* 下单方法
* userId用户编号、shopId商品编号
*/
public Result doOrder(Integer userId,Integer shopId){
// 进入当中后我们可以先查询是否还有商品存在,如果不存在的话,我们没有必要继续往下走了
int shopCount = shopService.queryShopCountByShopId(shopId); // 查询数量
// 已经没有库存了
if(shopCount < 1){
return Result.fail("已经售完!"); //直接返回信息
}
synchronized(userId.toString().intern()){ // 这里代表userId只要是相同的值,jvm就会锁住相同的值,而不是new的
// 取出当前代理对象进行方法调用
OrderServiceImpl proxy = (OrderServiceImpl)AopContext.currentProxy();
return proxy.toOrder(userId,shopId);
}
}
// 这里进行对应的库存扣减下单的具体业务
@Transactional
public Result toOrder(Integer userId,Integer shopId){
int userShopCount = shopService.selectUserDoShopByUserIdAndShopId(userId,shopId);
if(userShopCount > 0){
return Result.fail("您已经购买过了"); //直接返回信息
}
Order order = new Order(userId,shopId);
shopService.addOrder(shopId); // 这里的方法指的是编号为shopId的库存-1
return shopService.insert(Order);
}
}
这里面可能看到了AopContext.currentProxy去调用我们的方法,这个就关于我们的Spring事务机制了,大家都知道我们的事务是我们的代理实现的。然后这边我有两个方法,加了事务注解的方法被另外一个方法所调用了,而当前方法调用的话是通过的 this本身 ,那么在这里我们就要取出我们的代理对象来进行操作了!
同时我们要导入我们的aspect依赖哈!然后SpringBoot运行类上添加@EnableAspectJAutoProxy(exposeProxy=true)
这意思是将我们的代理对象暴露出来,默认是false不暴露