zoukankan      html  css  js  c++  java
  • 秒杀代码核心部分

      //内存标记,商品是否卖完
        private HashMap<Long, Boolean> localOverMap =  new HashMap<Long, Boolean>();
        
        /**
         * 系统初始化,加载商品库存,并为每个商品初始化内存标记
         * */
        public void afterPropertiesSet() throws Exception {  //该Controller实现InitializingBean
            List<GoodsVo> goodsList = goodsService.listGoodsVo();
            if(goodsList == null) {
                return;
            }
            for(GoodsVo goods : goodsList) {
                redisService.set(GoodsKey.getMiaoshaGoodsStock, ""+goods.getId(), goods.getStockCount());
                localOverMap.put(goods.getId(), false);
            }
        }
        
        //这里使用pathVariable,为了拼接动态路径,也是一种防刷手段
       @RequestMapping(value
    ="/{path}/do_miaosha", method=RequestMethod.POST) @ResponseBody public Result<Integer> miaosha(Model model,MiaoshaUser user, @RequestParam("goodsId")long goodsId, @PathVariable("path") String path) { model.addAttribute("user", user); if(user == null) { return Result.error(CodeMsg.SESSION_ERROR); } //验证path boolean check = miaoshaService.checkPath(user, goodsId, path); if(!check){ return Result.error(CodeMsg.REQUEST_ILLEGAL); } //内存标记,减少redis访问,如果没有这一步,也可以,直接去预减库存,但是,会造成redis的负担,所以加一个非线程安全的map,去做一层简单过滤 //同一时间,有可能100个人去抢最后一件商品(get为false),但是没关系,有redis的decr去做原子保障,保证不会超卖 boolean over = localOverMap.get(goodsId); if(over) { return Result.error(CodeMsg.MIAO_SHA_OVER); }
         //开始主流程:预减库存->判断重复秒杀->加入消息队列,返回成功(即排队中)
    //预减库存 long stock = redisService.decr(GoodsKey.getMiaoshaGoodsStock, ""+goodsId);//10 if(stock < 0) { localOverMap.put(goodsId, true); redisService.set(GoodsKey.getMiaoshaGoodsStock, ""+goodsId,0); return Result.error(CodeMsg.MIAO_SHA_OVER); } //判断是否已经秒杀到了 //redisService.set(OrderKey.getMiaoshaOrderByUidGid, ""+user.getId()+"_"+goods.getId(), miaoshaOrder); MiaoshaOrder order = orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(), goodsId); if(order != null) { redisService.incr(GoodsKey.getMiaoshaGoodsStock, ""+goodsId); localOverMap.put(goodsId, false); return Result.error(CodeMsg.REPEATE_MIAOSHA); } //入队 MiaoshaMessage mm = new MiaoshaMessage(); mm.setUser(user); mm.setGoodsId(goodsId);
         //消息队列发送者,发送消息 sender.sendMiaoshaMessage(mm);
    return Result.success(0);//排队中,用户点击秒杀后(内部去请求path,然后用path去请求秒杀服务,然后调轮询接口,查询结果) } /**做延迟任务setTimeOut,轮询秒杀结果 * orderId:成功 * -1:秒杀失败 * 0: 排队中 * */ @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); } @AccessLimit(seconds=5, maxCount=5, needLogin=true)//自定义注解,接口防刷 @RequestMapping(value="/path", method=RequestMethod.GET)//先获取path,才能请求秒杀接口 @ResponseBody public Result<String> getMiaoshaPath(HttpServletRequest request, MiaoshaUser user, @RequestParam("goodsId")long goodsId, @RequestParam(value="verifyCode", defaultValue="0")int verifyCode ) { if(user == null) { return Result.error(CodeMsg.SESSION_ERROR); } boolean check = miaoshaService.checkVerifyCode(user, goodsId, verifyCode); if(!check) { return Result.error(CodeMsg.REQUEST_ILLEGAL); } String path = miaoshaService.createMiaoshaPath(user, goodsId); return Result.success(path); } }
  • 相关阅读:
    【转】汽车CAN总线
    【转】I2C总线协议
    【转】SPI总线协议
    【转】结构struct 联合Union和枚举Enum的细节讨论
    复合类型变量其首地址的几种表示方式
    【转】四款经典3.7v锂电池充电电路图详解
    【转】crc16几种标准校验算法及c语言代码
    【转】 CRC循环冗余校验码
    对STM32库函数中 assert 函数的认知
    【转】用宏定义代替printf函数
  • 原文地址:https://www.cnblogs.com/brxHqs/p/9766820.html
Copyright © 2011-2022 走看看