Commit b3488624 by wuwenlong

下单防并发优化;

parent 681840e2
...@@ -24,6 +24,8 @@ public class Constants ...@@ -24,6 +24,8 @@ public class Constants
public static final String CONFIG_KEY_API_URL = "https://www.coujio.com"; //admin接口地址 public static final String CONFIG_KEY_API_URL = "https://www.coujio.com"; //admin接口地址
// 订单取消Key // 订单取消Key
public static final String ORDER_AUTO_CANCEL_KEY = "order_auto_cancel_key"; public static final String ORDER_AUTO_CANCEL_KEY = "order_auto_cancel_key";
// 订单锁定Key
public static final String ORDER_LOCK_KEY = "order_lock_key";
//测试环境,经测试需要,手机验证码测试环境可以不需要就能登录,value为1,则不验证验证码 //测试环境,经测试需要,手机验证码测试环境可以不需要就能登录,value为1,则不验证验证码
public static final String PHONE_TEST_KEY = "phone_test_key"; public static final String PHONE_TEST_KEY = "phone_test_key";
//通过uuid缓存的key 查找对应的 token数据 WX_TOKEN_USER:TOKEN //通过uuid缓存的key 查找对应的 token数据 WX_TOKEN_USER:TOKEN
......
...@@ -127,12 +127,10 @@ public class OrderTask { ...@@ -127,12 +127,10 @@ public class OrderTask {
String cancelStr; String cancelStr;
DateTime cancelTime; DateTime cancelTime;
cancelStr = sysConfigService.selectConfigByKey("order_cancel_time"); cancelStr = sysConfigService.selectConfigByKey("order_cancel_time");
if (StrUtil.isBlank(cancelStr)) { if (StrUtil.isBlank(cancelStr)) {
cancelStr = "1"; cancelStr = "5";
} }
cancelTime = cn.hutool.core.date.DateUtil.offset(sOrder.getCreateTime(), DateField.HOUR_OF_DAY, Integer.parseInt(cancelStr)); cancelTime = cn.hutool.core.date.DateUtil.offset(sOrder.getCreateTime(), DateField.MINUTE, Integer.parseInt(cancelStr));
long between = cn.hutool.core.date.DateUtil.between(cancelTime, cn.hutool.core.date.DateUtil.date(), DateUnit.SECOND, false); long between = cn.hutool.core.date.DateUtil.between(cancelTime, cn.hutool.core.date.DateUtil.date(), DateUnit.SECOND, false);
if (between < 0) {// 未到过期时间继续循环 if (between < 0) {// 未到过期时间继续循环
return Boolean.FALSE; return Boolean.FALSE;
...@@ -147,6 +145,7 @@ public class OrderTask { ...@@ -147,6 +145,7 @@ public class OrderTask {
couponUser.setUseStatus(CouponStatusEnum.NORMAL.getValue()); couponUser.setUseStatus(CouponStatusEnum.NORMAL.getValue());
consumerCouponService.updateById(couponUser); consumerCouponService.updateById(couponUser);
} }
logger.info(String.format("删除订单,订单号【%s】",sOrder.getOrderNo()));
return Boolean.TRUE; return Boolean.TRUE;
}); });
return execute; return execute;
......
...@@ -88,9 +88,6 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper, SOrder> impleme ...@@ -88,9 +88,6 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper, SOrder> impleme
private QPService qpService; private QPService qpService;
@Autowired @Autowired
private RedisUtil redisUtils;
@Autowired
private ISConsumptionRecordsService sConsumptionRecordsService; private ISConsumptionRecordsService sConsumptionRecordsService;
@Autowired @Autowired
...@@ -286,7 +283,7 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper, SOrder> impleme ...@@ -286,7 +283,7 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper, SOrder> impleme
queryWrapper.eq(SOrder::getRoomId, roomId); queryWrapper.eq(SOrder::getRoomId, roomId);
queryWrapper.notIn(SOrder::getRefundStatus, RefundStatusEnum.getRefundedStatus()); queryWrapper.notIn(SOrder::getRefundStatus, RefundStatusEnum.getRefundedStatus());
queryWrapper.in(SOrder::getStatus, OrderStatusEnum.getValidOrderStatus()); queryWrapper.in(SOrder::getStatus, OrderStatusEnum.getValidOrderStatus());
queryWrapper.eq(SOrder::getPayStatus, YesNoEnum.yes.getIndex()); queryWrapper.eq(SOrder::getIsDelete, YesNoEnum.no.getIndex());
String nowDayStr = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, day); String nowDayStr = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, day);
String nextDayStr = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, DateUtils.addDays(day, 1)); String nextDayStr = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, DateUtils.addDays(day, 1));
String yesterdayStr = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, DateUtils.addDays(day, -1)) + " 23"; String yesterdayStr = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, DateUtils.addDays(day, -1)) + " 23";
...@@ -302,100 +299,131 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper, SOrder> impleme ...@@ -302,100 +299,131 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper, SOrder> impleme
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public OrderPayResultResponse createOrder(CreateOrderRequest request) { public OrderPayResultResponse createOrder(CreateOrderRequest request) {
SConsumer user = FrontTokenComponent.getWxSConsumerEntry(); String lockResult = "";
if (ObjectUtil.isNull(user)) { try {
throw new BaseException("您的登录已过期,请先登录"); lockResult = lockOrder(request);
} SConsumer user = FrontTokenComponent.getWxSConsumerEntry();
SStore sStore = storeService.getById(request.getStoreId()); if (ObjectUtil.isNull(user)) {
//生成订单 throw new BaseException("您的登录已过期,请先登录");
SOrder sOrder = generatSOrder(request, user); }
//校验订单金额 SStore sStore = storeService.getById(request.getStoreId());
checkOrderPrice(sOrder, user); //生成订单
//校验订单预约时间 SOrder sOrder = generatSOrder(request, user);
checkOrderDate(request); //校验订单金额
//校验订单套餐 checkOrderPrice(sOrder, user);
checkOrderPack(request, user); //校验订单预约时间
SConsumerCoupon byId = null; checkOrderDate(request);
if (Objects.nonNull(request.getCouponId()) && request.getCouponId() != 0) { //校验订单套餐
byId = consumerCouponService.getById(request.getCouponId()); checkOrderPack(request, user);
if (Objects.nonNull(byId)) { SConsumerCoupon byId = null;
if (byId.getUseStatus().equals(UserStatusEnum.UNUSED.getCode())) { if (Objects.nonNull(request.getCouponId()) && request.getCouponId() != 0) {
if (StringUtils.isNotEmpty(byId.getCouponCode())) { byId = consumerCouponService.getById(request.getCouponId());
qpService.prepare(byId.getCouponCode(), sStore.getOpenShopUuid(), ConsumerCouponStatusEnum.ORDER.getCode()); if (Objects.nonNull(byId)) {
if (byId.getUseStatus().equals(UserStatusEnum.UNUSED.getCode())) {
if (StringUtils.isNotEmpty(byId.getCouponCode())) {
qpService.prepare(byId.getCouponCode(), sStore.getOpenShopUuid(), ConsumerCouponStatusEnum.ORDER.getCode());
}
} else {
throw new BaseException("优惠券已使用!");
} }
} else { } else {
throw new BaseException("优惠券已使用!"); throw new BaseException("优惠券不存在!");
} }
} else {
throw new BaseException("优惠券不存在!");
} }
} OrderPayResultResponse response = new OrderPayResultResponse();
OrderPayResultResponse response = new OrderPayResultResponse(); if (request.getPayFee().compareTo(BigDecimal.ZERO) <= 0) {
if (request.getPayFee().compareTo(BigDecimal.ZERO) <= 0) { response.setPayType(PayTypeEnum.WECHAT.getValue());
response.setPayType(PayTypeEnum.WECHAT.getValue()); response.setStatus(YesNoEnum.yes.getFlag());
response.setStatus(YesNoEnum.yes.getFlag()); response.setOrderNo(sOrder.getOrderNo());
response.setOrderNo(sOrder.getOrderNo()); sOrder.setPayStatus(YesNoEnum.yes.getIndex());
sOrder.setPayStatus(YesNoEnum.yes.getIndex()); sOrder.setPayTime(DateUtils.getNowDate());
sOrder.setPayTime(DateUtils.getNowDate()); } else {
} else {
// response = orderPayService.payment(sOrder); // response = orderPayService.payment(sOrder);
// 扫呗聚合支付 // 扫呗聚合支付
response = orderPayService.saobeiPayment(sOrder); response = orderPayService.saobeiPayment(sOrder);
// 加入自动未支付自动取消队列 // 加入自动未支付自动取消队列
redisUtil.lPush(Constants.ORDER_AUTO_CANCEL_KEY, sOrder.getOrderNo()); redisUtil.lPush(Constants.ORDER_AUTO_CANCEL_KEY, sOrder.getOrderNo());
} }
save(sOrder); save(sOrder);
if (response.getStatus().equals(YesNoEnum.yes.getFlag())) { if (response.getStatus().equals(YesNoEnum.yes.getFlag())) {
if (Objects.nonNull(byId)) { if (Objects.nonNull(byId)) {
if (StringUtils.isNotEmpty(byId.getCouponCode())) { if (StringUtils.isNotEmpty(byId.getCouponCode())) {
//验劵 //验劵
qpService.consume(byId.getCouponCode(), 1, sStore.getOpenShopUuid(), ConsumerCouponStatusEnum.ORDER.getCode()); qpService.consume(byId.getCouponCode(), 1, sStore.getOpenShopUuid(), ConsumerCouponStatusEnum.ORDER.getCode());
}
SConsumerCoupon consumerCoupon = new SConsumerCoupon();
consumerCoupon.setId(request.getCouponId());
consumerCoupon.setUseDate(new Date());
consumerCoupon.setUseStatus(UserStatusEnum.USED.getCode());
consumerCouponService.updateById(consumerCoupon);
}
wechatNewService.sendMiniSubscribeMessage(sOrder, MessageReminderEnum.RESERVER);
sConsumptionRecordsService.insertSConsumptionRecords(sOrder);
Map<String, String> map = new HashMap<>();
map.put("orderNo", sOrder.getOrderNo());
map.put("expirationTime", sOrder.getPreStartDate().toString());
JSONObject jsonObject = new JSONObject(map);
if (sOrder.getOrderType().equals(OrderTypeEnum.RESERVER.getCode())) {
redisUtil.set(ReceiptRdeisEnum.ORDER_NO.getValue() + sOrder.getOrderNo(), jsonObject.toString());
} }
SConsumerCoupon consumerCoupon = new SConsumerCoupon();
consumerCoupon.setId(request.getCouponId());
consumerCoupon.setUseDate(new Date());
consumerCoupon.setUseStatus(UserStatusEnum.USED.getCode());
consumerCouponService.updateById(consumerCoupon);
} }
wechatNewService.sendMiniSubscribeMessage(sOrder, MessageReminderEnum.RESERVER); if (sOrder.getOrderType().equals(OrderTypeEnum.RENEW.getCode())) {
sConsumptionRecordsService.insertSConsumptionRecords(sOrder); sOrder.setStartDate(sOrder.getPreStartDate());
Map<String, String> map = new HashMap<>(); sOrder.setEndDate(sOrder.getPreEndDate());
map.put("orderNo", sOrder.getOrderNo()); sOrder.setStatus(OrderStatusEnum.INUSE.getCode());
map.put("expirationTime", sOrder.getPreStartDate().toString()); //支付金额为0的
JSONObject jsonObject = new JSONObject(map); if (request.getPayFee().compareTo(BigDecimal.ZERO) <= 0) {
if (sOrder.getOrderType().equals(OrderTypeEnum.RESERVER.getCode())) { wechatNewService.sendMiniSubscribeMessage(sOrder, MessageReminderEnum.RESERVER);
redisUtils.set(ReceiptRdeisEnum.ORDER_NO.getValue() + sOrder.getOrderNo(), jsonObject.toString()); if (response.getStatus().equals(YesNoEnum.yes.getFlag())) {
baseMapper.updateById(sOrder);
//续费成功语音播报
deviceOpService.actionExecute(sOrder.getRoomId(), sOrder.getConsumerPhone(), VoiceEnum.RENEWAL_SUCCESS.getCode(),
cn.hutool.core.date.DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN),
cn.hutool.core.date.DateUtil.format(cn.hutool.core.date.DateUtil.offsetMinute(new Date(), 1), DatePattern.NORM_DATETIME_PATTERN), "1");
SRoom sRoom = roomService.getById(sOrder.getRoomId());
//通知保洁人员
sConsumerService.selectListByStoreId(sOrder.getStoreId()).stream().forEach(item -> {
// 循环发送短信提示门店保洁打扫卫生
smsService.sendSmsCleanRecordsStopRemind(item.getPhone(), sStore, sRoom);
});
}
}
Map<String, String> map = new HashMap<>();
map.put("orderNo", sOrder.getOrderNo());
map.put("expirationTime", sOrder.getEndDate().toString());
JSONObject jsonObject = new JSONObject(map);
redisUtil.set(ReceiptRdeisEnum.ORDER_NO_KEY.getValue() + sOrder.getOrderNo(), jsonObject.toString());
} }
return response;
}catch (BaseException e){
throw e;
}finally {
unLockOrder(request,lockResult);
} }
if (sOrder.getOrderType().equals(OrderTypeEnum.RENEW.getCode())) { }
sOrder.setStartDate(sOrder.getPreStartDate());
sOrder.setEndDate(sOrder.getPreEndDate()); private String lockOrder(CreateOrderRequest request) throws BaseException {
sOrder.setStatus(OrderStatusEnum.INUSE.getCode()); try {
//支付金额为0的 //自旋10次,每次等待1秒
if (request.getPayFee().compareTo(BigDecimal.ZERO) <= 0) { String lockResult = "";
wechatNewService.sendMiniSubscribeMessage(sOrder, MessageReminderEnum.RESERVER); for (int i = 0; i < 10; i++) {
if (response.getStatus().equals(YesNoEnum.yes.getFlag())) { lockResult = redisUtil.lockWithTimeout(Constants.ORDER_LOCK_KEY + request.getRoomId(), 11, 1);
baseMapper.updateById(sOrder); if (StringUtils.isBlank(lockResult)) {
//续费成功语音播报 Thread.sleep(1000L);
deviceOpService.actionExecute(sOrder.getRoomId(), sOrder.getConsumerPhone(), VoiceEnum.RENEWAL_SUCCESS.getCode(), } else {
cn.hutool.core.date.DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN), break;
cn.hutool.core.date.DateUtil.format(cn.hutool.core.date.DateUtil.offsetMinute(new Date(), 1), DatePattern.NORM_DATETIME_PATTERN), "1");
SRoom sRoom = roomService.getById(sOrder.getRoomId());
//通知保洁人员
sConsumerService.selectListByStoreId(sOrder.getStoreId()).stream().forEach(item -> {
// 循环发送短信提示门店保洁打扫卫生
smsService.sendSmsCleanRecordsStopRemind(item.getPhone(), sStore, sRoom);
});
} }
} }
Map<String, String> map = new HashMap<>(); return lockResult;
map.put("orderNo", sOrder.getOrderNo()); }catch (Exception e){
map.put("expirationTime", sOrder.getEndDate().toString()); throw new BaseException("当前房间下单太火爆了,请稍后再试!");
JSONObject jsonObject = new JSONObject(map);
redisUtils.set(ReceiptRdeisEnum.ORDER_NO_KEY.getValue() + sOrder.getOrderNo(), jsonObject.toString());
} }
}
return response; private void unLockOrder(CreateOrderRequest request,String keyValue) {
if(StringUtils.isNotBlank(keyValue)) {
redisUtil.unLock(Constants.ORDER_LOCK_KEY + request.getRoomId(), keyValue, 1);
}
} }
private void checkOrderPack(CreateOrderRequest request, SConsumer user) { private void checkOrderPack(CreateOrderRequest request, SConsumer user) {
...@@ -438,7 +466,8 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper, SOrder> impleme ...@@ -438,7 +466,8 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper, SOrder> impleme
LambdaQueryWrapper<SOrder> queryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<SOrder> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.notIn(SOrder::getRefundStatus, RefundStatusEnum.getRefundedStatus()); queryWrapper.notIn(SOrder::getRefundStatus, RefundStatusEnum.getRefundedStatus());
queryWrapper.in(SOrder::getStatus, OrderStatusEnum.getValidOrderStatus()); queryWrapper.in(SOrder::getStatus, OrderStatusEnum.getValidOrderStatus());
queryWrapper.eq(SOrder::getPayStatus, YesNoEnum.yes.getIndex()); // queryWrapper.eq(SOrder::getPayStatus, YesNoEnum.yes.getIndex());
queryWrapper.eq(SOrder::getIsDelete,YesNoEnum.no.getIndex());
queryWrapper.eq(SOrder::getStoreId, request.getStoreId()); queryWrapper.eq(SOrder::getStoreId, request.getStoreId());
queryWrapper.eq(SOrder::getRoomId, request.getRoomId()); queryWrapper.eq(SOrder::getRoomId, request.getRoomId());
switch (OrderTypeEnum.getEnumByCode(request.getOrderType())) { switch (OrderTypeEnum.getEnumByCode(request.getOrderType())) {
...@@ -737,14 +766,14 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper, SOrder> impleme ...@@ -737,14 +766,14 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper, SOrder> impleme
map.put("orderNo", sOrder.getOrderNo()); map.put("orderNo", sOrder.getOrderNo());
map.put("expirationTime", sOrder.getEndDate().toString()); map.put("expirationTime", sOrder.getEndDate().toString());
JSONObject jsonObject = new JSONObject(map); JSONObject jsonObject = new JSONObject(map);
redisUtils.set(ReceiptRdeisEnum.ORDER_NO_KEY.getValue() + sOrder.getOrderNo(), jsonObject.toString()); redisUtil.set(ReceiptRdeisEnum.ORDER_NO_KEY.getValue() + sOrder.getOrderNo(), jsonObject.toString());
} else if (sOrder.getOrderType().equals(OrderTypeEnum.RESERVER.getCode())) { } else if (sOrder.getOrderType().equals(OrderTypeEnum.RESERVER.getCode())) {
wechatNewService.sendMiniSubscribeMessage(sOrder, MessageReminderEnum.RESERVER); wechatNewService.sendMiniSubscribeMessage(sOrder, MessageReminderEnum.RESERVER);
Map<String, String> map = new HashMap<>(); Map<String, String> map = new HashMap<>();
map.put("orderNo", sOrder.getOrderNo()); map.put("orderNo", sOrder.getOrderNo());
map.put("expirationTime", sOrder.getPreStartDate().toString()); map.put("expirationTime", sOrder.getPreStartDate().toString());
JSONObject jsonObject = new JSONObject(map); JSONObject jsonObject = new JSONObject(map);
redisUtils.set(ReceiptRdeisEnum.ORDER_NO.getValue() + sOrder.getOrderNo(), jsonObject.toString()); redisUtil.set(ReceiptRdeisEnum.ORDER_NO.getValue() + sOrder.getOrderNo(), jsonObject.toString());
} }
baseMapper.updateById(sOrder); baseMapper.updateById(sOrder);
Long couponId = sOrder.getCouponId(); Long couponId = sOrder.getCouponId();
...@@ -823,7 +852,7 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper, SOrder> impleme ...@@ -823,7 +852,7 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper, SOrder> impleme
// 退款成功 // 退款成功
if (isRefund) { if (isRefund) {
// 删除redis 缓存信息,防止退款订单自动开始及给用户发送提示短信 // 删除redis 缓存信息,防止退款订单自动开始及给用户发送提示短信
redisUtils.delete(ReceiptRdeisEnum.ORDER_NO.getValue() + sOrder.getOrderNo()); redisUtil.delete(ReceiptRdeisEnum.ORDER_NO.getValue() + sOrder.getOrderNo());
//房间断电 //房间断电
deviceOpService.openOrCloseDevice(sOrder.getRoomId(), sOrder.getConsumerPhone(), OpTypeEnum.CUT_ELECTRIC.getCode(), true, 5); deviceOpService.openOrCloseDevice(sOrder.getRoomId(), sOrder.getConsumerPhone(), OpTypeEnum.CUT_ELECTRIC.getCode(), true, 5);
} }
...@@ -982,7 +1011,7 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper, SOrder> impleme ...@@ -982,7 +1011,7 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper, SOrder> impleme
map.put("orderNo", sOrder.getOrderNo()); map.put("orderNo", sOrder.getOrderNo());
map.put("expirationTime", sOrder.getEndDate().toString()); map.put("expirationTime", sOrder.getEndDate().toString());
JSONObject jsonObject = new JSONObject(map); JSONObject jsonObject = new JSONObject(map);
redisUtils.set(ReceiptRdeisEnum.ORDER_NO_KEY.getValue() + sOrder.getOrderNo(), jsonObject.toString()); redisUtil.set(ReceiptRdeisEnum.ORDER_NO_KEY.getValue() + sOrder.getOrderNo(), jsonObject.toString());
sOrder.setArrivalTime(new Date()); sOrder.setArrivalTime(new Date());
baseMapper.updateById(sOrder); baseMapper.updateById(sOrder);
//更改房间状态 //更改房间状态
...@@ -993,7 +1022,7 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper, SOrder> impleme ...@@ -993,7 +1022,7 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper, SOrder> impleme
Device device1 = new Device(); Device device1 = new Device();
device1.setRoomId(sOrder.getRoomId()); device1.setRoomId(sOrder.getRoomId());
device1.setDevType(DeviceType.DEVICE_0001.getCode()); device1.setDevType(DeviceType.DEVICE_0001.getCode());
redisUtils.delete(ReceiptRdeisEnum.ORDER_NO.getValue() + sOrder.getOrderNo()); redisUtil.delete(ReceiptRdeisEnum.ORDER_NO.getValue() + sOrder.getOrderNo());
//开门、取电 //开门、取电
deviceOpService.openDoor(sRoomVo.getId(), sOrder.getConsumerPhone()); deviceOpService.openDoor(sRoomVo.getId(), sOrder.getConsumerPhone());
//语音 //语音
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment