Browse Source

增加分布式锁30秒,防止并发抢订桌子

houweiyu 4 years ago
parent
commit
3b2b1ee283

+ 15 - 2
dinner-core/src/main/java/com/fdage/controller/app/AppOrderController.java

@@ -1,5 +1,6 @@
 package com.fdage.controller.app;
 
+import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.fdage.base.dto.OrderAndCanteenRspDto;
 import com.fdage.base.dto.OrderAppReqDto;
@@ -176,7 +177,7 @@ public class AppOrderController extends BaseController {
     }
     @PostMapping("/addNew")
     @ApiOperation(value = "创建订单")
-    public Result<TmOrder> addNew(@RequestBody OrderAppReqDto orderAppReqDto){
+    public Result<Object> addNew(@RequestBody OrderAppReqDto orderAppReqDto){
 
         if(null == orderAppReqDto){
             return Result.failure("入参缺失");
@@ -199,13 +200,25 @@ public class AppOrderController extends BaseController {
         if(StringUtils.isBlank(orderAppReqDto.getDeskId())){
             return Result.failure("桌子号缺失");
         }
+        //1、第一道互斥,如果当天已经有订单了,则直接互斥
         //TODO:这里可能会产生慢查询,需要优化
         List<TmOrder> dbOrderList = tmOrderService.getByTimeAndDeskId(orderAppReqDto.getDeskId() ,
                 orderAppReqDto.getReserveDate() , orderAppReqDto.getReserveTime());
         if(!CollectionUtils.isEmpty(dbOrderList) && dbOrderList.size() >= 1){
             return Result.failure("已经被预定,请选择其他");
         }
-        //TODO:这里需要加一个redis的分布式锁,用来实现抢桌子
+        //2、第二道互斥,通过分布式锁卡位
+        //分布式锁,这里不需要释放,没有释放别人的锁的问题存在,这里的锁,只做卡位用,不做库存变更使用
+        String redisLockKey = orderAppReqDto.getDeskId() + ":" + orderAppReqDto.getReserveDate();
+        log.info("redis的key={}" , redisLockKey);
+        boolean lockFlag = redisTemplate.opsForValue().setIfAbsent(redisLockKey , getContextUserInfo().getId() , 30 , TimeUnit.SECONDS);
+        log.info("抢锁结果:{}" , lockFlag);
+        if(!lockFlag){
+            log.info("抢锁失败,无法创建订单[{}]" , JSON.toJSONString(orderAppReqDto));
+            //抢锁失败
+            return Result.failure("抢订失败,请稍后重试");
+        }
+
         //校验短信验证码
         String redisAuthCodeKey = MSG_AUTH_CODE_REDIS_kEY + orderAppReqDto.getReserveUserPhone();
         String redisCOde = (String) redisTemplate.opsForValue().get(redisAuthCodeKey);

+ 29 - 30
dinner-core/src/main/java/com/fdage/controller/app/AppPayController.java

@@ -232,7 +232,12 @@ public class AppPayController extends BaseController {
                             throw new CommonBaseException(ResultCodeEnum.D101 , "更新订单为取消成功状态失败");
                         }
                         log.info("更新订单[{}]的支付状态为退款成功" , dbOrder.getId());
-                        TmDesk tmDesk = tmDeskService.getById(dbOrder.getDeskId());
+                        /**
+                         * 这里不再维护桌子的互斥变量了,因为一个变量只能维护一把锁,一个桌子一天可以有两个时间段被预定
+                         * 一把锁无法锁住所有,这里通过使用串化的思想,一个桌子只要有一个人进入预定流程,则直接认为卡住位置了
+                         * 其他人无法进入预定流程
+                         */
+                        /*TmDesk tmDesk = tmDeskService.getById(dbOrder.getDeskId());
                         if(null != tmDesk){
                             if(null == tmDesk.getStatus() || tmDesk.getStatus().compareTo(1) == 0){
                                 tmDesk.setStatus(0);
@@ -241,33 +246,11 @@ public class AppPayController extends BaseController {
                                 }
                                 log.info("更新桌子[{}]的状态为可预订" , tmDesk.getId());
                             }
-                        }
+                        }*/
                     }
                 }
                 return Result.failure("退款处理中," + return_msg);
             } else if (return_code.equalsIgnoreCase("SUCCESS")) {
-                String refundStatus = "";
-                //TODO:改成jdk8的形式
-                for ( String key : result.keySet()) {
-                    if(key.startsWith("refund_status_")){
-                        refundStatus = (String) result.get(key);
-                        break;
-                    }
-                }
-                if("SUCCESS".equals(refundStatus)){
-                    //退款成功,更新状态
-
-                    return Result.success( "退款成功");
-                }else if("REFUNDCLOSE".equals(refundStatus)){
-                    log.info("微信支付退款查询,微信返回退款关闭");
-                    //退款关闭
-                }else if("PROCESSING".equals(refundStatus)){
-                    //退款处理中
-                    log.info("微信支付退款查询,微信返回退款处理中");
-                }else if("CHANGE".equals(refundStatus)){
-                    //退款异常
-                    log.info("微信支付退款查询,微信返回退款异常");
-                }
                 boolean needUpdate = false;
                 if(null != dbOrder.getStatus()  && OrderStatusEnum.ORDER_CANCEL.getStatus().compareTo(dbOrder.getStatus()) != 0){
                     needUpdate = true;
@@ -283,7 +266,12 @@ public class AppPayController extends BaseController {
                         throw new CommonBaseException(ResultCodeEnum.D101 , "更新订单为取消成功状态失败");
                     }
                     log.info("更新订单[{}]的支付状态为退款成功" , dbOrder.getId());
-                    TmDesk tmDesk = tmDeskService.getById(dbOrder.getDeskId());
+                    /**
+                     * 这里不再维护桌子的互斥变量了,因为一个变量只能维护一把锁,一个桌子一天可以有两个时间段被预定
+                     * 一把锁无法锁住所有,这里通过使用串化的思想,一个桌子只要有一个人进入预定流程,则直接认为卡住位置了
+                     * 其他人无法进入预定流程
+                     */
+                    /*TmDesk tmDesk = tmDeskService.getById(dbOrder.getDeskId());
                     if(null != tmDesk){
                         if(null == tmDesk.getStatus() || tmDesk.getStatus().compareTo(1) == 0){
                             tmDesk.setStatus(0);
@@ -292,7 +280,7 @@ public class AppPayController extends BaseController {
                             }
                             log.info("更新桌子[{}]的状态为可预订" , tmDesk.getId());
                         }
-                    }
+                    }*/
                 }
             }
             return Result.success( "退款成功");
@@ -364,7 +352,12 @@ public class AppPayController extends BaseController {
             //更新订单的支付状态为已支付,同时跟新订单的状态为预定成功 TODO:这里二期需要改成:审核中
             tmOrderService.updateOrderStatusAndPayStatus(orderDetail ,
                     OrderPayStatusEnum.PAY_SUCCESS.getStatus() , OrderStatusEnum.ORDER_SUCCESS.getStatus());
-            if(StringUtils.isNotBlank(orderDetail.getDeskId())){
+            /**
+             * 这里不再维护桌子的互斥变量了,因为一个变量只能维护一把锁,一个桌子一天可以有两个时间段被预定
+             * 一把锁无法锁住所有,这里通过使用串化的思想,一个桌子只要有一个人进入预定流程,则直接认为卡住位置了
+             * 其他人无法进入预定流程
+             */
+            /*if(StringUtils.isNotBlank(orderDetail.getDeskId())){
                 //上锁,抢锁成功才可以
                 TmDesk tmDesk = tmDeskService.getBySelectForUpdate(orderDetail.getDeskId());
                 if(null != tmDesk){
@@ -380,7 +373,7 @@ public class AppPayController extends BaseController {
                     log.info("抢锁失败,订单[{}]无法预定桌子:[{}]" , orderDetail.getOrderNo() , orderDetail.getDeskName());
                     throw new CommonBaseException(ResultCodeEnum.D101 , "抢锁失败");
                 }
-            }
+            }*/
             return  Result.success("支付成功");
         } else if ("USERPAYING".equals(trade_state)) {
             //在途,正在支付中,则递归调用3次
@@ -459,7 +452,13 @@ public class AppPayController extends BaseController {
                     //TODO:收归重复代码
                     tmOrderService.updateOrderStatusAndPayStatus(dbOrder ,
                             OrderPayStatusEnum.PAY_SUCCESS.getStatus() , OrderStatusEnum.ORDER_SUCCESS.getStatus());
-                    if(StringUtils.isNotBlank(dbOrder.getDeskId())){
+
+                    /**
+                     * 这里不再维护桌子的互斥变量了,因为一个变量只能维护一把锁,一个桌子一天可以有两个时间段被预定
+                     * 一把锁无法锁住所有,这里通过使用串化的思想,一个桌子只要有一个人进入预定流程,则直接认为卡住位置了
+                     * 其他人无法进入预定流程
+                     */
+                    /*if(StringUtils.isNotBlank(dbOrder.getDeskId())){
                         //上锁,抢锁成功才可以
                         TmDesk tmDesk = tmDeskService.getBySelectForUpdate(dbOrder.getDeskId());
                         if(null != tmDesk){
@@ -474,7 +473,7 @@ public class AppPayController extends BaseController {
                             log.info("抢锁失败,订单[{}]无法预定桌子:[{}]" , dbOrder.getOrderNo() , dbOrder.getDeskName());
                             throw new CommonBaseException(ResultCodeEnum.D101 , "抢锁失败");
                         }
-                    }
+                    }*/
                 }
 
                 response.getWriter().write(DataUtils.setXml("SUCCESS", "OK"));