文章只展示部分核心代码,完整代码请参考源码


思路:减少数据库访问

1. 系统初始化,把商品库存数量加载到Redis

  1. public void afterPropertiesSet() throws Exception {
  2. List<GoodsVo> goodsList = goodsService.listGoodsVo();
  3. if (goodsList == null){
  4. return;
  5. }
  6. for (GoodsVo goods : goodsList) {
  7. redisService.set(GoodsKey.getMiaoshaGoodsStock,""+goods.getId(),goods.getStockCount());
  8. localOverMap.put(goods.getId(),false);
  9. }
  10. }

2.内存标记减少Redis访问

  1. private Map<Long,Boolean> localOverMap = new HashMap<Long, Boolean>();
  2. boolean over = localOverMap.get(goodsId);
  3. if (over){
  4. return Result.error(CodeMsg.MIAO_SHA_OVER);
  5. }
  1. 收到请求,Redis预减库存,库存不足,直接返回,否则进入4

    1. Long stock = redisService.decr(GoodsKey.getMiaoshaGoodsStock, "" + goodsId);
    2. if (stock < 0){
    3. localOverMap.put(goodsId,true);//标记
    4. return Result.error(CodeMsg.MIAO_SHA_OVER);
    5. }

    3. 请求入队缓存,异步下单,立即返回排队中

    1. //入队
    2. MiaoshaMessage mm = new MiaoshaMessage();
    3. mm.setUser(user);
    4. mm.setGoodsId(goodsId);
    5. sender.sendMiaoshaMessage(mm);
    6. return Result.success(0);//排队中

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

    1. @RabbitListener(queues=MQConfig.MIAOSHA_QUEUE)
    2. public void receive(String message) {
    3. log.info("receive message:"+message);
    4. MiaoshaMessage mm = RedisService.stringToBean(message, MiaoshaMessage.class);
    5. MiaoshaUser user = mm.getUser();
    6. long goodsId = mm.getGoodsId();
    7. GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);
    8. int stock = goods.getStockCount();
    9. if(stock <= 0) {
    10. return;
    11. }
    12. //判断是否已经秒杀到了
    13. MiaoshaOrder order = orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(), goodsId);
    14. if(order != null) {
    15. return;
    16. }
    17. //减库存 下订单 写入秒杀订单
    18. miaoshaService.miaosha(user, goods);
    19. }

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

    ```javascript success:function(data){ if(data.code == 0){

    1. var result = data.data;
    2. if (result < 0) {
    3. layer.msg("对不起,秒杀失败");
    4. }else if (result == 0) {//继续轮询
    5. setTimeout(function () {
    6. getMiaoshaResult(goodsId);
    7. },50);
    8. }else {
    9. layer.confirm("恭喜你秒杀成功!查看订单?",{btn:["确定","取消"]},
    10. function () {
    11. window.location.href="/order_detail.htm?orderId="+result;
    12. },
    13. function () {
    14. layer.closeAll();
    15. });
    16. }

    }else{

     layer.msg(data.msg);
    

    } },

function getMiaoshaResult(goodsId) { g_showLoading(); $.ajax({ url:”/miaosha/result”, type:”GET”, data:{ goodsId:$(“#goodsId”).val(), }, success:function(data){ if(data.code == 0){ var result = data.data; if (result < 0) { layer.msg(“对不起,秒杀失败”); }else if (result == 0) {//继续轮询 setTimeout(function () { getMiaoshaResult(goodsId); },50); }else { layer.confirm(“恭喜你秒杀成功!查看订单?”,{btn:[“确定”,”取消”]}, function () { window.location.href=”/order_detail.htm?orderId=”+result; }, function () { layer.closeAll(); }); } }else{ layer.msg(data.msg); } }, error:function(){ layer.msg(“客户端请求有误”); } }); } ```