rabbitMQ

消息队列,通过一定的通信协议,生产者和消费者在应用程序内传递通信。

主要的作用,提高负载,减耦合。

场景描述:当点击秒杀按钮的那个时刻,有很高的并发量,客户端发出请求之后,会判断库存,如果库存大于0,就判断是否已经下单,如果没有下单,就执行秒杀逻辑,对于秒杀逻辑,分两个步骤,一是减库存,二是创建订单。

以上就是不使用rabbitMQ的场景描述。

利用消息队列,我们可以在执行秒杀逻辑之前,将用户和待秒杀的商品进行入队(rabbitMQ的生产者类),然后将秒杀逻辑放在出队上(rabbitMQ的消费者类)

在客户端页面上创建一个轮询函数,每隔一段时间,设置一个请求是否有秒杀结果,然后进行数据展示,或者跳转。

 

通过以上操作,我们可以将用户的请求与返回的结果通过rabbitMQ进行解耦合。从而降低网站的并发。

 

  • 内存标记库存

  假如后面的操作已经确认库存小于0,则设置一个标记器,直接返回错误信息。

//内存标记,第一次拦截
        Boolean over = localOverMap.get(goodsId);
        if(over){
            return Result.error(CodeMsg.MIAO_SHA_OVER);
        }

 

 

  • 预减库存

  该操作相当于一个拦截器,当我们的秒杀请求进到秒杀控制器中,需要先从redis中减库存,然后判断库存是否充足。因此,需要先在redis中加载商品的库存数

  这里利用控制器继承一个接口,来写一个系统初始化的方法,将商品的库存数放到redis中,每次从秒杀点击过来的请求,先加载该初始化方法,把库存数从数据库里拿出来,(这里可以改进为从缓存中拿值),然后判断库存数,如果库存数小于0,则不需要后续操作,直接返回错误。

/**
     * 系统初始化
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {

        //得到商品的所有列表
        List<GoodsVo> goodsList = goodsService.listGoodsVo();
        if(goodsList==null){
            return;
        }

        for (GoodsVo goods : goodsList) {
            redisService.set(GoodsKey.getMiaoshaGoodsStock,""+goods.getId(),goods.getStockCount());
            //对内存进行标志,若没有结束库存就是false,若有库存就是true
            localOverMap.put(goods.getId(),false);//false表示有库存
        }

    }


//预减库存
        Long stock = redisService.decr(GoodsKey.getMiaoshaGoodsStock, "" + goodsId);
        if(stock<0){
            localOverMap.put(goodsId,true);
            return Result.error(CodeMsg.MIAO_SHA_OVER);
        }

 

当判断,既有库存,又没有下订单,则执行入队操作,将需要传递的用户和商品名加入到队列中,传递给消费者。

//判断是否已经秒杀到了
        MiaoshaOrder order=orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(), goodsId);
        if(order!=null){
            return Result.error(CodeMsg.REPEATE_MIAOSHA);
        }

        //入队操作
        //创建需要入队的数据类,需要用户类和商品的id。
        MiaoshaMessage message=new MiaoshaMessage();
        message.setGoodsId(goodsId);
        message.setUser(user);
        //调用rabbitMQ生产者的发送方法,发送该数据类
        mqSender.sendMiaoshaMessage(message);

 

  • 完整MiaoshaController类

@Controller
@RequestMapping("/miaosha")
public class MiaoshaController implements InitializingBean{


    @Autowired
    private GoodsService goodsService;

    @Autowired
    private OrderService orderService;

    @Autowired
    private MiaoshaService miaoshaService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private MQSender mqSender;



    private HashMap<Long,Boolean> localOverMap=new HashMap<>();

    /**
     * 系统初始化
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {

        //得到商品的所有列表
        List<GoodsVo> goodsList = goodsService.listGoodsVo();
        if(goodsList==null){
            return;
        }

        for (GoodsVo goods : goodsList) {
            redisService.set(GoodsKey.getMiaoshaGoodsStock,""+goods.getId(),goods.getStockCount());
            //对内存进行标志,若没有结束库存就是false,若有库存就是true
            localOverMap.put(goods.getId(),false);//false表示有库存
        }

    }

    @RequestMapping(value = "/do_miaosha",method = RequestMethod.POST)
    @ResponseBody
    public Result<Integer> list(Model model, MiaoshaUser user,
                       @RequestParam("goodsId") long goodsId){

        model.addAttribute("user",user);
        if(user==null){
            //如果没有获取到user值,报异常
            return Result.error(CodeMsg.SESSION_ERROR);
        }


        //内存标记,第一次拦截
        Boolean over = localOverMap.get(goodsId);
        if(over){
            return Result.error(CodeMsg.MIAO_SHA_OVER);
        }

        //预减库存
        Long stock = redisService.decr(GoodsKey.getMiaoshaGoodsStock, "" + goodsId);
        if(stock<0){
            localOverMap.put(goodsId,true);
            return Result.error(CodeMsg.MIAO_SHA_OVER);
        }

        //判断是否已经秒杀到了
        MiaoshaOrder order=orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(), goodsId);
        if(order!=null){
            return Result.error(CodeMsg.REPEATE_MIAOSHA);
        }

        //入队操作
        //创建需要入队的数据类,需要用户类和商品的id。
        MiaoshaMessage message=new MiaoshaMessage();
        message.setGoodsId(goodsId);
        message.setUser(user);
        //调用rabbitMQ生产者的发送方法,发送该数据类
        mqSender.sendMiaoshaMessage(message);

        return Result.success(0);//返回0代表排队中









//        //判断库存
//        GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);
//        Integer stock= goods.getStockCount();
//
//        if(stock<=0){
//            model.addAttribute("errmsg", CodeMsg.MIAO_SHA_OVER.getMsg());
//            return Result.error(CodeMsg.MIAO_SHA_OVER);
//        }
//
//        //判断是否已经秒杀到了
//        MiaoshaOrder order=orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(), goodsId);
//
//        if(order!=null){
//            return Result.error(CodeMsg.REPEATE_MIAOSHA);
//        }
//
//        //进行秒杀逻辑
//        //减库存,下订单,写入秒杀订单
//        OrderInfo orderInfo=miaoshaService.miaosha(user, goods);

//        return Result.success(orderInfo);
    }


    @RequestMapping(value="/result", method=RequestMethod.GET)
    @ResponseBody
    public Result<Long> miaoshaResult(Model model,MiaoshaUser user,
                                      @RequestParam("goodsId")long goodsId){
        model.addAttribute("user",user);
        if(user==null){
            return Result.error(CodeMsg.SESSION_ERROR);
        }
        //获取秒杀的结果
        long result  =miaoshaService.getMiaoshaResult(user.getId(), goodsId);

        return Result.success(result);
    }


}
View Code

相关文章:

  • 2019-03-27
  • 2021-09-05
  • 2021-12-28
  • 2021-04-20
  • 2022-12-23
  • 2022-12-23
  • 2021-11-14
猜你喜欢
  • 2021-12-18
  • 2021-12-28
  • 2021-10-29
  • 2021-04-28
  • 2022-12-23
  • 2021-12-19
  • 2022-12-23
相关资源
相似解决方案