소스 검색

增加定时任务

houweiyu 4 년 전
부모
커밋
68f92bb510

+ 2 - 0
dinner-application/src/main/java/com/fdage/DinnerReservationApplication.java

@@ -11,6 +11,7 @@ import org.springframework.boot.builder.SpringApplicationBuilder;
 import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
 import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Bean;
 import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
 import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
+import org.springframework.scheduling.annotation.EnableScheduling;
 
 
 import java.time.LocalDateTime;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeFormatter;
@@ -25,6 +26,7 @@ import java.time.format.DateTimeFormatter;
 @MapperScan(basePackages = {"com.fdage.base.dao"})
 @MapperScan(basePackages = {"com.fdage.base.dao"})
 /*@EnableFeignClients
 /*@EnableFeignClients
 @EnableDiscoveryClient*/
 @EnableDiscoveryClient*/
+@EnableScheduling
 public class DinnerReservationApplication  extends SpringBootServletInitializer {
 public class DinnerReservationApplication  extends SpringBootServletInitializer {
 
 
 
 

+ 2 - 0
dinner-core/src/main/java/com/fdage/base/enums/OrderStatusEnum.java

@@ -13,6 +13,8 @@ public enum  OrderStatusEnum {
     ORDER_FAIL(3 , "预定失败"),
     ORDER_FAIL(3 , "预定失败"),
     ORDER_CANCEL(4 , "预定取消"),
     ORDER_CANCEL(4 , "预定取消"),
     ORDER_USED(5 , "已用餐"),
     ORDER_USED(5 , "已用餐"),
+    ORDER_PAY_TIMEOUT(6 , "支付超时"),
+    ORDER_USE_TIMEOUT(7 , "已失效")
     ;
     ;
 
 
     private Integer status;
     private Integer status;

+ 13 - 0
dinner-core/src/main/java/com/fdage/base/service/impl/TmDeskServiceImpl.java

@@ -41,6 +41,19 @@ public class TmDeskServiceImpl extends ServiceImpl<TmDeskDao, TmDesk> implements
     }
     }
 
 
     @Transactional(rollbackFor = Exception.class)
     @Transactional(rollbackFor = Exception.class)
+    public TmDesk getBySelectForUpdate(String deskId){
+        if(StringUtils.isBlank(deskId)){
+            return null;
+        }
+        LambdaQueryWrapper<TmDesk> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+        lambdaQueryWrapper.eq(TmDesk::getIsDelete , 0);
+        lambdaQueryWrapper.eq(TmDesk::getId , deskId);
+        lambdaQueryWrapper.last("for update");
+        return getBaseMapper().selectOne(lambdaQueryWrapper);
+
+    }
+
+    @Transactional(rollbackFor = Exception.class)
     public int updateWithId(TmDesk tmDesk){
     public int updateWithId(TmDesk tmDesk){
         if(null == tmDesk || null == tmDesk.getId()){
         if(null == tmDesk || null == tmDesk.getId()){
             return -1;
             return -1;

+ 65 - 0
dinner-core/src/main/java/com/fdage/base/service/impl/TmOrderServiceImpl.java

@@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fdage.base.dao.TmOrderDao;
 import com.fdage.base.dao.TmOrderDao;
 import com.fdage.base.entity.TmOrder;
 import com.fdage.base.entity.TmOrder;
 import com.fdage.base.enums.IdPreEnum;
 import com.fdage.base.enums.IdPreEnum;
+import com.fdage.base.enums.OrderPayStatusEnum;
 import com.fdage.base.enums.OrderStatusEnum;
 import com.fdage.base.enums.OrderStatusEnum;
 import com.fdage.base.service.ITmOrderService;
 import com.fdage.base.service.ITmOrderService;
 import com.fdage.base.utils.DataUtils;
 import com.fdage.base.utils.DataUtils;
@@ -17,6 +18,8 @@ import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.transaction.annotation.Transactional;
 
 
+import java.time.Instant;
+import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
@@ -41,6 +44,68 @@ public class TmOrderServiceImpl extends ServiceImpl<TmOrderDao, TmOrder> impleme
         return getBaseMapper().selectPage(page , lambdaQueryWrapper);
         return getBaseMapper().selectPage(page , lambdaQueryWrapper);
     }
     }
 
 
+    public List<TmOrder> getUnUserOrder(){
+        LambdaQueryWrapper<TmOrder> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+        lambdaQueryWrapper.eq(TmOrder::getIsDelete , 0);
+        lambdaQueryWrapper.eq(TmOrder::getStatus , OrderStatusEnum.ORDER_SUCCESS.getStatus());
+        lambdaQueryWrapper.eq(TmOrder::getPayStatus , OrderPayStatusEnum.PAY_SUCCESS.getStatus());
+        lambdaQueryWrapper.eq(TmOrder::getReserveDate , LocalDate.now().minusDays(1));
+        //TODO:以后需要根据数据量做调整
+        lambdaQueryWrapper.last("limit 500");
+        return getBaseMapper().selectList(lambdaQueryWrapper);
+
+    }
+
+    public List<TmOrder> getFiveMinAgoUnPayOrderList(){
+        LambdaQueryWrapper<TmOrder> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+        lambdaQueryWrapper.eq(TmOrder::getIsDelete , 0);
+        lambdaQueryWrapper.eq(TmOrder::getStatus , OrderStatusEnum.ORDER_ING.getStatus());
+        lambdaQueryWrapper.in(TmOrder::getPayStatus , OrderPayStatusEnum.REFUND_ING.getStatus() , OrderPayStatusEnum.PAY_FAIL.getStatus() ,
+                OrderPayStatusEnum.UNPAID.getStatus());
+        LocalDateTime fiveMinAgo =  LocalDateTime.now().minusMinutes(5L);
+        lambdaQueryWrapper.le(TmOrder::getCreateTime , fiveMinAgo).or().eq(TmOrder::getCreateTime , fiveMinAgo);
+        //TODO:以后需要根据数据量做调整
+        lambdaQueryWrapper.last("limit 500");
+        return getBaseMapper().selectList(lambdaQueryWrapper);
+
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public TmOrder getSelectByUpdate(String orderId){
+        if(StringUtils.isBlank(orderId)){
+            return null;
+        }
+        LambdaQueryWrapper<TmOrder> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+        lambdaQueryWrapper.eq(TmOrder::getId , orderId);
+        lambdaQueryWrapper.eq(TmOrder::getIsDelete , 0);
+        lambdaQueryWrapper.last("for update");
+        return getBaseMapper().selectOne(lambdaQueryWrapper);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public TmOrder getSelectByUpdateByOrderSn(String orderNo){
+        if(StringUtils.isBlank(orderNo)){
+            return null;
+        }
+        LambdaQueryWrapper<TmOrder> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+        lambdaQueryWrapper.eq(TmOrder::getOrderNo , orderNo);
+        lambdaQueryWrapper.eq(TmOrder::getIsDelete , 0);
+        lambdaQueryWrapper.last("for update");
+        return getBaseMapper().selectOne(lambdaQueryWrapper);
+    }
+
+    public List<TmOrder> getByTimeAndDeskId(String deskId , LocalDate reserveDate , LocalDateTime
+                                              reserveDateTime){
+        LambdaQueryWrapper<TmOrder> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+        lambdaQueryWrapper.eq(TmOrder::getDeskId , deskId);
+        lambdaQueryWrapper.eq(TmOrder::getReserveDate , reserveDate);
+        lambdaQueryWrapper.eq(TmOrder::getReserveTime , reserveDateTime);
+        lambdaQueryWrapper.in(TmOrder::getStatus , OrderStatusEnum.ORDER_ING.getStatus() , OrderStatusEnum.ORDER_AUDITED.getStatus(),
+                OrderStatusEnum.ORDER_SUCCESS.getStatus() , OrderStatusEnum.ORDER_SUCCESS.getStatus());
+        lambdaQueryWrapper.orderByDesc(TmOrder::getCreateTime);
+        return getBaseMapper().selectList(lambdaQueryWrapper);
+    }
+
     public TmOrder getLatestByDesk(String deskId){
     public TmOrder getLatestByDesk(String deskId){
         if(StringUtils.isBlank(deskId)){
         if(StringUtils.isBlank(deskId)){
             return null;
             return null;

+ 10 - 1
dinner-core/src/main/java/com/fdage/controller/app/AppOrderController.java

@@ -158,7 +158,7 @@ public class AppOrderController extends BaseController {
         //执行退款逻辑
         //执行退款逻辑
         WechatRefundApiResult result = WechatUtil.wxRefund(dbOrder.getOrderNo(), refundId ,
         WechatRefundApiResult result = WechatUtil.wxRefund(dbOrder.getOrderNo(), refundId ,
                 dbOrder.getOrderPrice().doubleValue(), dbOrder.getOrderPrice().doubleValue());
                 dbOrder.getOrderPrice().doubleValue(), dbOrder.getOrderPrice().doubleValue());
-        if (null != result && result.getResult_code().equals("SUCCESS")) {
+        if (null != result && null != result.getResult_code() && result.getResult_code().equals("SUCCESS")) {
             dbOrder.setPayStatus(OrderPayStatusEnum.REFUND_ING.getStatus());
             dbOrder.setPayStatus(OrderPayStatusEnum.REFUND_ING.getStatus());
             dbOrder.setUpdateTime(LocalDateTime.now());
             dbOrder.setUpdateTime(LocalDateTime.now());
             if(tmOrderService.updateWithId(dbOrder) != 1){
             if(tmOrderService.updateWithId(dbOrder) != 1){
@@ -196,6 +196,15 @@ public class AppOrderController extends BaseController {
         if(StringUtils.isBlank(orderAppReqDto.getMsgCode())){
         if(StringUtils.isBlank(orderAppReqDto.getMsgCode())){
             return Result.failure("短信验证码缺失");
             return Result.failure("短信验证码缺失");
         }
         }
+        if(StringUtils.isBlank(orderAppReqDto.getDeskId())){
+            return Result.failure("桌子号缺失");
+        }
+        //TODO:这里可能会产生慢查询,需要优化
+        List<TmOrder> dbOrderList = tmOrderService.getByTimeAndDeskId(orderAppReqDto.getDeskId() ,
+                orderAppReqDto.getReserveDate() , orderAppReqDto.getReserveTime());
+        if(!CollectionUtils.isEmpty(dbOrderList) && dbOrderList.size() >= 1){
+            return Result.failure("已经被预定,请选择其他");
+        }
         //校验短信验证码
         //校验短信验证码
         String redisAuthCodeKey = MSG_AUTH_CODE_REDIS_kEY + orderAppReqDto.getReserveUserPhone();
         String redisAuthCodeKey = MSG_AUTH_CODE_REDIS_kEY + orderAppReqDto.getReserveUserPhone();
         String redisCOde = (String) redisTemplate.opsForValue().get(redisAuthCodeKey);
         String redisCOde = (String) redisTemplate.opsForValue().get(redisAuthCodeKey);

+ 54 - 10
dinner-core/src/main/java/com/fdage/controller/app/AppPayController.java

@@ -170,7 +170,7 @@ public class AppPayController extends BaseController {
             @ApiImplicitParam(name = "orderId", value = "订单号", paramType = "query", required = true, dataType = "String")
             @ApiImplicitParam(name = "orderId", value = "订单号", paramType = "query", required = true, dataType = "String")
     })
     })
     public Object refund(@RequestParam(name = "orderId") String orderId) {
     public Object refund(@RequestParam(name = "orderId") String orderId) {
-
+        log.info("==============进入微信退款结果查询接口==============");
         if(StringUtils.isBlank(orderId)){
         if(StringUtils.isBlank(orderId)){
             return Result.failure("订单号不能为空");
             return Result.failure("订单号不能为空");
         }
         }
@@ -314,14 +314,20 @@ public class AppPayController extends BaseController {
     @PostMapping("query")
     @PostMapping("query")
     @Transactional(rollbackFor = Exception.class)
     @Transactional(rollbackFor = Exception.class)
     public Object orderQuery(@RequestParam(name = "orderId") String orderId) {
     public Object orderQuery(@RequestParam(name = "orderId") String orderId) {
+        log.info("==============进入微信支付结果查询接口==============");
         if (orderId == null) {
         if (orderId == null) {
             return Result.failure("订单不存在");
             return Result.failure("订单不存在");
         }
         }
 
 
-        TmOrder orderDetail = tmOrderService.getById(orderId);
+        TmOrder orderDetail = tmOrderService.getSelectByUpdate(orderId);
         if(null == orderDetail){
         if(null == orderDetail){
-            return Result.failure("订单获取失败");
+            return Result.failure("抢锁失败,订单获取失败");
+        }
+
+        if(null != orderDetail.getPayStatus() && OrderPayStatusEnum.PAY_SUCCESS.getStatus().compareTo(orderDetail.getPayStatus()) == 0){
+            return Result.success("支付成功");
         }
         }
+
         Map<Object, Object> parame = new TreeMap<Object, Object>();
         Map<Object, Object> parame = new TreeMap<Object, Object>();
         parame.put("appid", ResourceUtil.getConfigByName("wx.appId"));
         parame.put("appid", ResourceUtil.getConfigByName("wx.appId"));
         // 商家账号。
         // 商家账号。
@@ -359,16 +365,20 @@ public class AppPayController extends BaseController {
             tmOrderService.updateOrderStatusAndPayStatus(orderDetail ,
             tmOrderService.updateOrderStatusAndPayStatus(orderDetail ,
                     OrderPayStatusEnum.PAY_SUCCESS.getStatus() , OrderStatusEnum.ORDER_SUCCESS.getStatus());
                     OrderPayStatusEnum.PAY_SUCCESS.getStatus() , OrderStatusEnum.ORDER_SUCCESS.getStatus());
             if(StringUtils.isNotBlank(orderDetail.getDeskId())){
             if(StringUtils.isNotBlank(orderDetail.getDeskId())){
-                TmDesk tmDesk = tmDeskService.getById(orderDetail.getDeskId());
+                //上锁,抢锁成功才可以
+                TmDesk tmDesk = tmDeskService.getBySelectForUpdate(orderDetail.getDeskId());
                 if(null != tmDesk){
                 if(null != tmDesk){
                     if(null != tmDesk.getStatus() && tmDesk.getStatus().compareTo(1) != 0){
                     if(null != tmDesk.getStatus() && tmDesk.getStatus().compareTo(1) != 0){
                         tmDesk.setStatus(1);
                         tmDesk.setStatus(1);
                         tmDesk.setUpdateTime(LocalDateTime.now());
                         tmDesk.setUpdateTime(LocalDateTime.now());
-                        if(!tmDeskService.updateById(tmDesk)){
+                        if(tmDeskService.updateWithId(tmDesk) != 1){
                             throw new CommonBaseException(ResultCodeEnum.D101 , "更细桌子/包厢状态失败");
                             throw new CommonBaseException(ResultCodeEnum.D101 , "更细桌子/包厢状态失败");
                         }
                         }
 
 
                     }
                     }
+                }else{
+                    log.info("抢锁失败,订单[{}]无法预定桌子:[{}]" , orderDetail.getOrderNo() , orderDetail.getDeskName());
+                    throw new CommonBaseException(ResultCodeEnum.D101 , "抢锁失败");
                 }
                 }
             }
             }
             return  Result.success("支付成功");
             return  Result.success("支付成功");
@@ -402,6 +412,7 @@ public class AppPayController extends BaseController {
     @ApiIgnore
     @ApiIgnore
     @RequestMapping(value = "/notify", method = RequestMethod.POST, produces = "text/html;charset=UTF-8")
     @RequestMapping(value = "/notify", method = RequestMethod.POST, produces = "text/html;charset=UTF-8")
     public void notify(HttpServletRequest request, HttpServletResponse response) {
     public void notify(HttpServletRequest request, HttpServletResponse response) {
+        log.info("==============收到微信支付的回调==============");
         try {
         try {
             request.setCharacterEncoding("UTF-8");
             request.setCharacterEncoding("UTF-8");
             response.setCharacterEncoding("UTF-8");
             response.setCharacterEncoding("UTF-8");
@@ -423,15 +434,48 @@ public class AppPayController extends BaseController {
             String result_code = result.getResult_code();
             String result_code = result.getResult_code();
             if (result_code.equalsIgnoreCase("FAIL")) {
             if (result_code.equalsIgnoreCase("FAIL")) {
                 //订单编号
                 //订单编号
-                String out_trade_no = result.getOut_trade_no();
-                log.info("订单" + out_trade_no + "支付失败");
+                String orderNo = result.getOut_trade_no();
+                log.info("订单" + orderNo + "支付失败");
+                //更新订单的状态为支付失败,并更新库存
+                TmOrder dbOrder = tmOrderService.getSelectByUpdateByOrderSn(orderNo);
+                if(null == dbOrder){
+                    //抢锁失败
+                    log.info("收到支付通知为支付失败,但是抢锁失败,不做操作,待查询的时候做更新");
+                }else{
+                    tmOrderService.updateOrderStatusAndPayStatus(dbOrder ,
+                            OrderPayStatusEnum.PAY_FAIL.getStatus() , OrderStatusEnum.ORDER_ING.getStatus());
+                }
                 response.getWriter().write(DataUtils.setXml("SUCCESS", "OK"));
                 response.getWriter().write(DataUtils.setXml("SUCCESS", "OK"));
             } else if (result_code.equalsIgnoreCase("SUCCESS")) {
             } else if (result_code.equalsIgnoreCase("SUCCESS")) {
                 //订单编号
                 //订单编号
-                String out_trade_no = result.getOut_trade_no();
-                log.info("订单" + out_trade_no + "支付成功");
+                String orderNo = result.getOut_trade_no();
+                log.info("订单" + orderNo + "支付成功");
                 //更新订单的状态为已支付,并更新库存
                 //更新订单的状态为已支付,并更新库存
-
+                TmOrder dbOrder = tmOrderService.getSelectByUpdateByOrderSn(orderNo);
+                if(null == dbOrder){
+                    //抢锁失败
+                    log.info("收到支付通知为支付成功,但是抢锁失败,不做操作,待查询的时候做更新");
+                }else{
+                    //TODO:收归重复代码
+                    tmOrderService.updateOrderStatusAndPayStatus(dbOrder ,
+                            OrderPayStatusEnum.PAY_SUCCESS.getStatus() , OrderStatusEnum.ORDER_SUCCESS.getStatus());
+                    if(StringUtils.isNotBlank(dbOrder.getDeskId())){
+                        //上锁,抢锁成功才可以
+                        TmDesk tmDesk = tmDeskService.getBySelectForUpdate(dbOrder.getDeskId());
+                        if(null != tmDesk){
+                            if(null != tmDesk.getStatus() && tmDesk.getStatus().compareTo(1) != 0){
+                                tmDesk.setStatus(1);
+                                tmDesk.setUpdateTime(LocalDateTime.now());
+                                if(tmDeskService.updateWithId(tmDesk) != 1){
+                                    throw new CommonBaseException(ResultCodeEnum.D101 , "更细桌子/包厢状态失败");
+                                }
+                            }
+                        }else{
+                            log.info("抢锁失败,订单[{}]无法预定桌子:[{}]" , dbOrder.getOrderNo() , dbOrder.getDeskName());
+                            throw new CommonBaseException(ResultCodeEnum.D101 , "抢锁失败");
+                        }
+                    }
+                }
 
 
                 response.getWriter().write(DataUtils.setXml("SUCCESS", "OK"));
                 response.getWriter().write(DataUtils.setXml("SUCCESS", "OK"));
             }
             }

+ 61 - 0
dinner-core/src/main/java/com/fdage/task/InvalidateOrderTask.java

@@ -0,0 +1,61 @@
+package com.fdage.task;
+
+import com.fdage.base.entity.TmOrder;
+import com.fdage.base.enums.OrderStatusEnum;
+import com.fdage.base.service.impl.TmOrderServiceImpl;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 2 * @Author: Abner
+ * 3 * @Date: 2021/3/4 20:00
+ * 4 每隔5分钟检测超过5分钟未付款的订单,并作废此订单
+ *
+ *   //TODO:这里需要声明专用的线程池,不使用默认的线程池
+ */
+@Component
+@EnableScheduling
+@Async
+@Slf4j
+public class InvalidateOrderTask {
+
+    @Autowired
+    private TmOrderServiceImpl orderService;
+
+    /**
+     * 每隔5分钟执行一次
+     * */
+    @Scheduled(cron = "*/30 * * * * ?")
+    @Transactional(rollbackFor = Exception.class)
+    public void doTask(){
+        log.info("========订单超5分钟未支付检测定时任务=======开始执行=====");
+        //捞取状态为:预定中,状态为(付款中、付款失败、未付款的订单)
+        //如果超过5分钟不支付,默认翻转为6(支付超时),此单作废
+        List<TmOrder> unPayTimeoutOrderList = orderService.getFiveMinAgoUnPayOrderList();
+        int count = 0;
+        if(!CollectionUtils.isEmpty(unPayTimeoutOrderList)){
+            for ( TmOrder order : unPayTimeoutOrderList) {
+                TmOrder dbOrder = orderService.getSelectByUpdate(order.getId());
+                if(null == dbOrder){
+                    log.info("订单[{}]抢锁失败,无法将其更新为超时未支付状态" , order.getOrderNo());
+                }else{
+                    dbOrder.setStatus(OrderStatusEnum.ORDER_PAY_TIMEOUT.getStatus());
+                    orderService.updateWithId(dbOrder);
+                    count += 1;
+                }
+            }
+        }
+        log.info("========订单超5分钟未支付检测定时任务========执行完成{}个====" , count);
+
+    }
+
+}

+ 79 - 0
dinner-core/src/main/java/com/fdage/task/ReInitDeskStatusTask.java

@@ -0,0 +1,79 @@
+package com.fdage.task;
+
+import com.fdage.base.entity.TmDesk;
+import com.fdage.base.entity.TmOrder;
+import com.fdage.base.enums.OrderStatusEnum;
+import com.fdage.base.service.impl.TmDeskServiceImpl;
+import com.fdage.base.service.impl.TmOrderServiceImpl;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+/**
+ * 2 * @Author: Abner
+ * 3 * @Date: 2021/3/4 20:08
+ * 4 每日凌晨重置已经预定成功,但是未来消费的订单的状态
+ *  //TODO:这里需要声明专用的线程池,不使用默认的线程池
+ */
+@Component
+@EnableScheduling
+@Async
+@Slf4j
+public class ReInitDeskStatusTask {
+
+    @Autowired
+    private TmOrderServiceImpl orderService;
+
+    @Autowired
+    private TmDeskServiceImpl deskService;
+
+    /**
+     * 默认是fixedDelay 上一次执行完毕时间后执行下一轮
+     * 凌晨0点到1点之间,每隔15分钟执行一次
+     * 支持幂等
+     */
+    @Scheduled(cron = "0 */5 0-1 * * ?")
+    @Transactional(rollbackFor = Exception.class)
+    public void run() throws InterruptedException {
+        log.info("========每日凌晨初始化未使用的预定订单定时任务=====开始执行=======");
+        List<TmOrder> unUsedOrderList = orderService.getUnUserOrder();
+        int count = 0;
+        if(!CollectionUtils.isEmpty(unUsedOrderList)){
+            for ( TmOrder order  : unUsedOrderList) {
+                TmOrder dbOrder = orderService.getSelectByUpdate(order.getId());
+                if(null == dbOrder){
+                    log.info("订单[{}]抢锁失败,无法将其更新为已失效的状态" , order.getOrderNo());
+                }else{
+                    if(StringUtils.isNotBlank(dbOrder.getDeskId())){
+                        TmDesk desk = deskService.getBySelectForUpdate(dbOrder.getDeskId());
+                        if(null == desk){
+                            log.info("订单[{}]的预定桌子[{}]抢锁失败,暂时不初始化" , dbOrder.getId() , dbOrder.getDeskId());
+                        }else{
+                            if(null == desk.getStatus() || desk.getStatus().compareTo(1) == 1){
+                                desk.setStatus(0);
+                                int update = deskService.updateWithId(desk);
+                                if(update == 1){
+                                    dbOrder.setStatus(OrderStatusEnum.ORDER_USE_TIMEOUT.getStatus());
+                                    orderService.updateWithId(dbOrder);
+                                    count += 1;
+                                }
+                            }
+
+                        }
+                    }
+
+                }
+            }
+        }
+
+        log.info("========每日凌晨初始化未使用的预定订单定时任务=====执行完成{}个=======" , count);
+    }
+}