Commit b3488624 by wuwenlong

下单防并发优化;

parent 681840e2
......@@ -24,6 +24,8 @@ public class Constants
public static final String CONFIG_KEY_API_URL = "https://www.coujio.com"; //admin接口地址
// 订单取消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,则不验证验证码
public static final String PHONE_TEST_KEY = "phone_test_key";
//通过uuid缓存的key 查找对应的 token数据 WX_TOKEN_USER:TOKEN
......
......@@ -127,12 +127,10 @@ public class OrderTask {
String cancelStr;
DateTime cancelTime;
cancelStr = sysConfigService.selectConfigByKey("order_cancel_time");
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);
if (between < 0) {// 未到过期时间继续循环
return Boolean.FALSE;
......@@ -147,6 +145,7 @@ public class OrderTask {
couponUser.setUseStatus(CouponStatusEnum.NORMAL.getValue());
consumerCouponService.updateById(couponUser);
}
logger.info(String.format("删除订单,订单号【%s】",sOrder.getOrderNo()));
return Boolean.TRUE;
});
return execute;
......
......@@ -88,9 +88,6 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper, SOrder> impleme
private QPService qpService;
@Autowired
private RedisUtil redisUtils;
@Autowired
private ISConsumptionRecordsService sConsumptionRecordsService;
@Autowired
......@@ -286,7 +283,7 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper, SOrder> impleme
queryWrapper.eq(SOrder::getRoomId, roomId);
queryWrapper.notIn(SOrder::getRefundStatus, RefundStatusEnum.getRefundedStatus());
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 nextDayStr = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, DateUtils.addDays(day, 1));
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
@Override
@Transactional(rollbackFor = Exception.class)
public OrderPayResultResponse createOrder(CreateOrderRequest request) {
SConsumer user = FrontTokenComponent.getWxSConsumerEntry();
if (ObjectUtil.isNull(user)) {
throw new BaseException("您的登录已过期,请先登录");
}
SStore sStore = storeService.getById(request.getStoreId());
//生成订单
SOrder sOrder = generatSOrder(request, user);
//校验订单金额
checkOrderPrice(sOrder, user);
//校验订单预约时间
checkOrderDate(request);
//校验订单套餐
checkOrderPack(request, user);
SConsumerCoupon byId = null;
if (Objects.nonNull(request.getCouponId()) && request.getCouponId() != 0) {
byId = consumerCouponService.getById(request.getCouponId());
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());
String lockResult = "";
try {
lockResult = lockOrder(request);
SConsumer user = FrontTokenComponent.getWxSConsumerEntry();
if (ObjectUtil.isNull(user)) {
throw new BaseException("您的登录已过期,请先登录");
}
SStore sStore = storeService.getById(request.getStoreId());
//生成订单
SOrder sOrder = generatSOrder(request, user);
//校验订单金额
checkOrderPrice(sOrder, user);
//校验订单预约时间
checkOrderDate(request);
//校验订单套餐
checkOrderPack(request, user);
SConsumerCoupon byId = null;
if (Objects.nonNull(request.getCouponId()) && request.getCouponId() != 0) {
byId = consumerCouponService.getById(request.getCouponId());
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 {
throw new BaseException("优惠券已使用!");
throw new BaseException("优惠券不存在!");
}
} else {
throw new BaseException("优惠券不存在!");
}
}
OrderPayResultResponse response = new OrderPayResultResponse();
if (request.getPayFee().compareTo(BigDecimal.ZERO) <= 0) {
response.setPayType(PayTypeEnum.WECHAT.getValue());
response.setStatus(YesNoEnum.yes.getFlag());
response.setOrderNo(sOrder.getOrderNo());
sOrder.setPayStatus(YesNoEnum.yes.getIndex());
sOrder.setPayTime(DateUtils.getNowDate());
} else {
OrderPayResultResponse response = new OrderPayResultResponse();
if (request.getPayFee().compareTo(BigDecimal.ZERO) <= 0) {
response.setPayType(PayTypeEnum.WECHAT.getValue());
response.setStatus(YesNoEnum.yes.getFlag());
response.setOrderNo(sOrder.getOrderNo());
sOrder.setPayStatus(YesNoEnum.yes.getIndex());
sOrder.setPayTime(DateUtils.getNowDate());
} else {
// response = orderPayService.payment(sOrder);
// 扫呗聚合支付
response = orderPayService.saobeiPayment(sOrder);
// 加入自动未支付自动取消队列
redisUtil.lPush(Constants.ORDER_AUTO_CANCEL_KEY, sOrder.getOrderNo());
}
save(sOrder);
if (response.getStatus().equals(YesNoEnum.yes.getFlag())) {
if (Objects.nonNull(byId)) {
if (StringUtils.isNotEmpty(byId.getCouponCode())) {
//验劵
qpService.consume(byId.getCouponCode(), 1, sStore.getOpenShopUuid(), ConsumerCouponStatusEnum.ORDER.getCode());
// 扫呗聚合支付
response = orderPayService.saobeiPayment(sOrder);
// 加入自动未支付自动取消队列
redisUtil.lPush(Constants.ORDER_AUTO_CANCEL_KEY, sOrder.getOrderNo());
}
save(sOrder);
if (response.getStatus().equals(YesNoEnum.yes.getFlag())) {
if (Objects.nonNull(byId)) {
if (StringUtils.isNotEmpty(byId.getCouponCode())) {
//验劵
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);
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())) {
redisUtils.set(ReceiptRdeisEnum.ORDER_NO.getValue() + sOrder.getOrderNo(), jsonObject.toString());
if (sOrder.getOrderType().equals(OrderTypeEnum.RENEW.getCode())) {
sOrder.setStartDate(sOrder.getPreStartDate());
sOrder.setEndDate(sOrder.getPreEndDate());
sOrder.setStatus(OrderStatusEnum.INUSE.getCode());
//支付金额为0的
if (request.getPayFee().compareTo(BigDecimal.ZERO) <= 0) {
wechatNewService.sendMiniSubscribeMessage(sOrder, MessageReminderEnum.RESERVER);
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());
sOrder.setStatus(OrderStatusEnum.INUSE.getCode());
//支付金额为0的
if (request.getPayFee().compareTo(BigDecimal.ZERO) <= 0) {
wechatNewService.sendMiniSubscribeMessage(sOrder, MessageReminderEnum.RESERVER);
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);
});
}
private String lockOrder(CreateOrderRequest request) throws BaseException {
try {
//自旋10次,每次等待1秒
String lockResult = "";
for (int i = 0; i < 10; i++) {
lockResult = redisUtil.lockWithTimeout(Constants.ORDER_LOCK_KEY + request.getRoomId(), 11, 1);
if (StringUtils.isBlank(lockResult)) {
Thread.sleep(1000L);
} else {
break;
}
}
Map<String, String> map = new HashMap<>();
map.put("orderNo", sOrder.getOrderNo());
map.put("expirationTime", sOrder.getEndDate().toString());
JSONObject jsonObject = new JSONObject(map);
redisUtils.set(ReceiptRdeisEnum.ORDER_NO_KEY.getValue() + sOrder.getOrderNo(), jsonObject.toString());
return lockResult;
}catch (Exception e){
throw new BaseException("当前房间下单太火爆了,请稍后再试!");
}
}
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) {
......@@ -438,7 +466,8 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper, SOrder> impleme
LambdaQueryWrapper<SOrder> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.notIn(SOrder::getRefundStatus, RefundStatusEnum.getRefundedStatus());
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::getRoomId, request.getRoomId());
switch (OrderTypeEnum.getEnumByCode(request.getOrderType())) {
......@@ -737,14 +766,14 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper, SOrder> impleme
map.put("orderNo", sOrder.getOrderNo());
map.put("expirationTime", sOrder.getEndDate().toString());
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())) {
wechatNewService.sendMiniSubscribeMessage(sOrder, MessageReminderEnum.RESERVER);
Map<String, String> map = new HashMap<>();
map.put("orderNo", sOrder.getOrderNo());
map.put("expirationTime", sOrder.getPreStartDate().toString());
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);
Long couponId = sOrder.getCouponId();
......@@ -823,7 +852,7 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper, SOrder> impleme
// 退款成功
if (isRefund) {
// 删除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);
}
......@@ -982,7 +1011,7 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper, SOrder> impleme
map.put("orderNo", sOrder.getOrderNo());
map.put("expirationTime", sOrder.getEndDate().toString());
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());
baseMapper.updateById(sOrder);
//更改房间状态
......@@ -993,7 +1022,7 @@ public class SOrderServiceImpl extends ServiceImpl<SOrderMapper, SOrder> impleme
Device device1 = new Device();
device1.setRoomId(sOrder.getRoomId());
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());
//语音
......
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