簡介
當秒殺請求被放入queue中后,由於MySQL處理能力有限,可能需要等待一段時間才能完成對秒殺請求的處理;這段時間前端會不斷詢問秒殺請求的處理結果。
1.在前端定義輪詢函數。
每隔50ms,調用“/miaosha/getresult”接口,傳入參數goodsId,當秒殺成功時提示是否查看訂單頁面,當秒殺失敗是顯示失敗信息,當秒殺請求
仍在處理中時,等待50ms后再次查詢。
1 //輪詢功能:每隔50ms,查看一次是否秒殺成功 2 function getResult(goodsId) { 3 g_showLoading(); 4 $.ajax({ 5 url:"/miaosha/getresult", 6 type:"GET", 7 data:{ 8 goodsId:$("#goodsId").val(), 9 }, 10 success:function (data){ 11 var result = data.data; 12 if (result<0){ 13 layer.msg("對不起,秒殺失敗"); 14 }else if (result==0){ 15 setTimeout(function () { 16 getResult(goodsId); 17 },50) 18 } else { 19 layer.confirm("恭喜你,秒殺成功。查看訂單?",{btn:["確定","取消"]}, 20 function () { 21 window.location.href="/order_detail.htm?orderId="+result; 22 }, 23 function () { 24 layer.closeAll(); 25 26 }); 27 } 28 29 }, 30 error:function () { 31 layer.msg(data.msg); 32 } 33 }); 34 35 }
2.后端getResult方法會返回秒殺的處理結果
成功:返回訂單id;失敗:返回-1,表示沒有庫存了;正在處理中:返回0。
1 /* 2 * 輪詢功能:查看秒殺的結果 3 * */ 4 @AccessLimit(seconds = 5,maxCount = 5) 5 @RequestMapping(value = "/getresult",method = RequestMethod.GET) 6 @ResponseBody 7 public Result<Long> getResult(Model model,MiaoshaUser user,@RequestParam("goodsId")long goodsId) { 8 //判斷現在的秒殺狀態 9 long result = miaoshaService.getMiaoshaResult(user.getId(),goodsId); 10 11 return Result.success(result); 12 }
3.miaoshaService.java中的getMiaoshaResult()方法才是真正獲取秒殺結果的方法
該方法的參數有兩個,goodsId,userId。此兩個參數將被用來查詢使用。
在該方法中進行兩次判斷,第一次,goodsId+userId相對應的秒殺訂單是否存在,存在返回訂單號;不存在,進行第二次
第二次,判斷減庫存的情況,減庫存失敗就返回秒殺失敗,其它的情況就認為正在處理中。
1 //輪詢中判斷秒殺的狀態 2 public long getMiaoshaResult(Long userId, long goodsId) { 3 //1.判斷秒殺是否成功 4 OrderInfo orderInfo = orderInfoService.getByUserIdGoodsId(userId,goodsId); 5 if (orderInfo != null) { 6 return orderInfo.getId(); //秒殺成功返回訂單id 7 } 8 //2.如果不成功,判斷是否秒殺失敗或秒殺進行中 9 if (!getReduceResult(goodsId)) { 10 return -1; //沒有庫存,秒殺失敗 11 }else return 0; //有庫存,正在秒殺 12 }
在第二次判斷中,需要使用getResult()函數,此函數為獲取減庫存結果的函數,並且還有一個與之對應的setResult()函數用來保存減庫存結果。
1 private void setReduceResult(long goodsId, boolean reduceResult) { 2 redisService.set(ReduceResultPrefix.getReduceResult,""+goodsId,reduceResult); 3 } 4 5 private boolean getReduceResult(long goodsId) { 6 return redisService.exists(ReduceResultPrefix.getReduceResult,""+goodsId); 7 }
在減庫存的操作過后調用setReduceResult方法,將減庫存的結果,緩存到redis中。
1 //三步走:減庫存,下訂單,寫入秒殺訂單 2 @Transactional 3 public OrderInfo miaoSha(long useId, long goodsId) { 4 //減庫存,並設置減庫存的結果 5 boolean reduceResult=miaoshaGoodsService.reduceStock(goodsId); 6 miaoshaGoodsService.reduceFMStock(goodsId); 7 setReduceResult(goodsId,reduceResult); 8 if (!reduceResult) { 9 return null; 10 }
其中miaoshaGoodsService.reduceStock(goodsId);會調用ORM框架的update操作去減庫存;
而update操作會返回影響的行數,如果返回值為1,代表減庫存成功;返回值為0,代表減庫存失敗。
在miaoshaGoodsService.reduceStock()方法中會將0,1轉化為false,true作為返回值,然后賦值給reduceResult變量。
然后將reduceResult變量緩存入redis中。