Java高并发秒杀之接口优化

在这里插入图片描述

接口优化

Redis预减库存减少数据库的访问
内存标记减少redis访问
请求先入队缓冲,异步下单,增强用户体验
RabbitMQ安装与Spring Boot集成
1、Redis预减库存减少数据库的访问
顾名思义,Redis预减库存减少数据库的访问的思想就是减少对数据库的访问。

  • (1)系统初始化时,将商品库存信息加载到redis中;
  • (2)服务端收到请求后,redis预减库存,如果库存不足,则直接进入下一步;
  • (3)服务端将请求入队,立即返回向客户端返回排队中的信息,提高用户体验;
  • (4)服务端请求出队,生成秒杀订单,减少库存;
  • (5)最后客户端轮询是否秒杀成功。

系统初始化,把商品库存数量加载到Redis
实现接口 InitializingBean

public class MiaoshaController implements InitializingBean{

实现方法

@Override
public void afterPropertiesSet() throws Exception {
    List<GoodsVo> goodsVoList =  goodsService.listGoodsVo();
    if (goodsVoList==null){
        return ;
         }
    for (GoodsVo goodsVo : goodsVoList){
        //将商品库存加载到redis中  
          redisService.set(GoodsKey.getMiaoshaGoodsStock,""+goodsVo.getId(),goodsVo.getStockCount());
    }
}      

服务端收到请求后,redis预减库存,如果库存不足,则直接进入下一步

//减少库存
long stock = redisService.decr(GoodsKey.getMiaoshaGoodsStock,""+goodsId);
if (stock<0){//如果没有库存了就返回秒杀失败了。
    return Result.error(CodeMsg.MIAO_SHA_OVER);
}
//判断是否秒杀到了。
MiaoshaOrder order  = orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(),goodsId);
    if(order!=null) {//已经秒杀到了
        return Result.error(CodeMsg.REPEATE_MIAOSHA);
    }
//入队
MiaoshaMessage mm = new MiaoshaMessage();
mm.setGoodsId(goodsId);
mm.setUser(user);
mqSender.sendMiaoshaMessage(mm);
return  Result.success(0);//排队中
}

请求出队,生成订单,减少库存

@RabbitListener(queues = MQConfig.MIAOSHA_QUEUE)
    public void receiver(String message) {
        log.info("recevier" + message);
        //将消息还原为bean对象
        MiaoshaMessage mm = redisService.stringToBean(message, MiaoshaMessage.class);
        MiaoshaUser user = mm.getUser();
        long goodsId = mm.getGoodsId();
        //减库存,订单
        GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);
        int stock = goods.getGoodsStock();
        if (stock <= 0) {//没有库存了.
            return;
        }
              //判断是否重复秒杀
        MiaoshaOrder order = orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(), goodsId);
        if (order != null) {
            return;
        } else {
         //秒杀
            //减库存 下订单 写入秒杀订单
             miaoshaService.miaosha(user, goods);
        }

    }  

客户端轮询,是否秒杀成功

@RequestMapping("/result")
    public Result miaoshResult(Model model, MiaoshaUser user, @RequestParam("goodsId") long goodsId) {
        //没登录就跳转到登录页面
        model.addAttribute("user", user);
        if (user == null) {
         return Result.error(CodeMsg.SESSION_ERROR);
        }
//查询下是否生成了订单
        long rsult = miaoshaService.getMiaoshResult(user.getId(), goodsId);
        return Result.success(rsult);
}

2、内存标记减少redis访问

在MiaoshaController定义一个HashMap<Long, Boolean>,在某一商品已经秒杀结束时,在HashMap中对该商品的库存进行标记,如果库存为0,则将该商品标记为已经秒杀结束。然后在从redis中读取库存信息前做一次判断,如果该商品已经秒杀结束,则不用在访问redis中的库存信息。

private HashMap<Long, Boolean> localOverMap =  new HashMap<Long, Boolean>();
//内存标记,减少redis访问
     boolean over = localOverMap.get(goodsId);
     if(over) {
      return Result.error(CodeMsg.MIAO_SHA_OVER);
     }

3、请求先入队缓冲,异步下单,增强用户体验

服务器收到秒杀请求后,将请求放置在队列中,提高用户体验。然后秒杀请求出队,服务器生成秒杀订单,减少缓存中的库存。

具体过程:
如果秒杀商品库存尚有,则生成一条秒杀消息发送到消息队列中;
消息的消费者收到秒杀消息后,从数据库中读取用户是否已经完成秒杀,如果没有,则减库存,下订单,写入订单信息到数据库中。

©️2020 CSDN 皮肤主题: 程序猿惹谁了 设计师:上身试试 返回首页