|
|
@@ -55,6 +55,7 @@ import com.sqx.modules.errand.entity.TbIndentSmsSendLog;
|
|
|
import com.sqx.modules.errand.service.TbIndentService;
|
|
|
import com.sqx.modules.errand.service.TbIndentSmsSendLogService;
|
|
|
import com.sqx.modules.errand.service.TbIndentSmsTemplateService;
|
|
|
+import com.sqx.modules.goods.bo.StockUpdateItemBO;
|
|
|
import com.sqx.modules.goods.dao.GoodsDao;
|
|
|
import com.sqx.modules.goods.dao.GoodsShopDao;
|
|
|
import com.sqx.modules.goods.dao.GoodsShopRelevancyDao;
|
|
|
@@ -636,33 +637,75 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 乐观锁扣减库存 - 独立事务
|
|
|
+ * 允许负数,不检查库存
|
|
|
+ */
|
|
|
@Override
|
|
|
- public void subStock(TbOrder tbOrder) {
|
|
|
- Long shopId1 = tbOrder.getShopId();
|
|
|
- Long orderId = tbOrder.getOrderId();
|
|
|
- List<OrderGoods> orderGoodsList = orderGoodsDao.selectList(
|
|
|
- new QueryWrapper<OrderGoods>()
|
|
|
- .eq("order_id", orderId));
|
|
|
- for (int a = 0; a < orderGoodsList.size(); a++) {
|
|
|
- Integer goodsNum = orderGoodsList.get(a).getGoodsNum();
|
|
|
- Long goodsId = orderGoodsList.get(a).getGoodsId();
|
|
|
- GoodsShopRelevancy goodsShopRelevancy = goodsShopRelevancyDao.selectOne(
|
|
|
- new QueryWrapper<GoodsShopRelevancy>()
|
|
|
- .eq("shop_id", shopId1)
|
|
|
- .eq("goods_id", goodsId));
|
|
|
- GoodsShopRelevancy goodsShopRelevancy1 = new GoodsShopRelevancy();
|
|
|
- goodsShopRelevancy1.setId(goodsShopRelevancy.getId());
|
|
|
+ @Transactional(propagation = Propagation.REQUIRES_NEW)
|
|
|
+ public void subStock(TbOrder order) {
|
|
|
+ Long orderId = order.getOrderId();
|
|
|
|
|
|
- //加销量
|
|
|
- goodsShopRelevancy1.setSales(goodsShopRelevancy.getSales() + goodsNum);
|
|
|
+ log.info("订单{}开始乐观锁扣减库存", orderId);
|
|
|
|
|
|
- //减库存
|
|
|
- goodsShopRelevancy1.setInventory(goodsShopRelevancy.getInventory() - goodsNum);
|
|
|
- goodsShopRelevancyDao.updateById(goodsShopRelevancy1);
|
|
|
- // goodsShopDao.updateShopSales(1, goodsNum, goodsShopRelevancy.getShopId());
|
|
|
- }
|
|
|
+ try {
|
|
|
+ // 1. 获取订单商品并聚合
|
|
|
+ List<OrderGoods> orderGoodsList = orderGoodsDao.selectList(
|
|
|
+ new QueryWrapper<OrderGoods>().eq("order_id", orderId));
|
|
|
|
|
|
-// goodsShopDao.updateShopSales(1, 1, tbOrder.getShopId());
|
|
|
+ if (orderGoodsList.isEmpty()) {
|
|
|
+ log.warn("订单{}没有商品", orderId);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 按商品ID聚合数量
|
|
|
+ Map<Long, Integer> goodsNumMap = orderGoodsList.stream()
|
|
|
+ .collect(Collectors.groupingBy(
|
|
|
+ OrderGoods::getGoodsId,
|
|
|
+ Collectors.summingInt(OrderGoods::getGoodsNum)
|
|
|
+ ));
|
|
|
+
|
|
|
+ // 3. 批量查询当前版本号
|
|
|
+ List<Long> goodsIds = new ArrayList<>(goodsNumMap.keySet());
|
|
|
+ List<GoodsShopRelevancy> currentStocks = goodsShopRelevancyDao.selectBatchWithVersion(goodsIds);
|
|
|
+
|
|
|
+ // 4. 构建版本号Map
|
|
|
+ Map<Long, Integer> versionMap = currentStocks.stream()
|
|
|
+ .collect(Collectors.toMap(
|
|
|
+ GoodsShopRelevancy::getId,
|
|
|
+ GoodsShopRelevancy::getVersion
|
|
|
+ ));
|
|
|
+
|
|
|
+ // 5. 构建更新项
|
|
|
+ List<StockUpdateItemBO> updateItems = new ArrayList<>();
|
|
|
+ for (Map.Entry<Long, Integer> entry : goodsNumMap.entrySet()) {
|
|
|
+ Long goodsId = entry.getKey();
|
|
|
+ Integer num = entry.getValue();
|
|
|
+ Integer version = versionMap.get(goodsId);
|
|
|
+
|
|
|
+ if (version == null) {
|
|
|
+ log.warn("商品{}不存在", goodsId);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ updateItems.add(new StockUpdateItemBO(goodsId, num, version));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 6. 执行批量乐观锁更新
|
|
|
+ int updated = goodsShopRelevancyDao.batchOptimisticUpdateStock(updateItems);
|
|
|
+
|
|
|
+ boolean success = updated == updateItems.size();
|
|
|
+
|
|
|
+ if (success) {
|
|
|
+ log.info("订单{}库存扣减成功,更新{}个商品", orderId, updated);
|
|
|
+ } else {
|
|
|
+ // 允许更新失败,继续处理其他商品
|
|
|
+ log.warn("订单{}部分商品更新失败,预期{},实际{}", orderId, updateItems.size(), updated);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("订单{}库存扣减异常", orderId, e);
|
|
|
+ throw new SqxException("库存扣减失败", e);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@@ -675,12 +718,6 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
|
|
|
// 店铺信息
|
|
|
GoodsShop goodsShop = shopMessageService.getShopInfoById(order.getShopId());
|
|
|
|
|
|
- // 小程序推送设置
|
|
|
- CommonInfo mpPushConfig = commonInfoService.findOne(269);
|
|
|
-
|
|
|
- // 用户信息
|
|
|
- UserEntity userEntity = userDao.selectById(order.getUserId());
|
|
|
-
|
|
|
// 是否自动接单
|
|
|
boolean autoAccept = goodsShop.getAutoAcceptOrder() != null && goodsShop.getAutoAcceptOrder() == 0;
|
|
|
// 是否预约订单
|
|
|
@@ -706,9 +743,6 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
|
|
|
// 更新订单状态及订单序号
|
|
|
updateOrderStatusAndSequence(order);
|
|
|
|
|
|
- // 扣减库存
|
|
|
- this.subStock(order);
|
|
|
-
|
|
|
// 优惠券变成已使用状态
|
|
|
updateCouponState(order);
|
|
|
|
|
|
@@ -719,15 +753,6 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
|
|
|
if (order.getStatus() == 6) {
|
|
|
// 如果是外卖订单,则生成一个跑腿的订单
|
|
|
tbIndentService.insertIndent(order);
|
|
|
-
|
|
|
- // 发送商家接单通知
|
|
|
- MyGlobalThreadPool.execute(() -> {
|
|
|
- try {
|
|
|
- sendOrderAcceptMessage(order, goodsShop, mpPushConfig, userEntity);
|
|
|
- } catch (Exception e) {
|
|
|
- log.error("订单:{},商家接单通知发送失败,失败原因:{}", order.getOrderId(), e);
|
|
|
- }
|
|
|
- });
|
|
|
}
|
|
|
|
|
|
// 在锁中提交事务
|
|
|
@@ -742,8 +767,27 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
|
|
|
lock.unlock();
|
|
|
}
|
|
|
|
|
|
- // 添加消息记录并且进行推送
|
|
|
MyGlobalThreadPool.execute(() -> {
|
|
|
+ // 扣减库存,允许部分超卖,后续再优化超卖问题
|
|
|
+ try {
|
|
|
+ this.subStock(order);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("订单:{},扣减库存失败,失败原因:{}", order.getOrderId(), e);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 小程序推送设置
|
|
|
+ CommonInfo mpPushConfig = commonInfoService.findOne(269);
|
|
|
+ // 用户信息
|
|
|
+ UserEntity userEntity = userDao.selectById(order.getUserId());
|
|
|
+
|
|
|
+ // 发送商家接单通知
|
|
|
+ try {
|
|
|
+ sendOrderAcceptMessage(order, goodsShop, mpPushConfig, userEntity);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("订单:{},商家接单通知发送失败,失败原因:{}", order.getOrderId(), e);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 添加消息记录并且进行推送
|
|
|
try {
|
|
|
addOrderMessageAndPush(order, goodsShop, mpPushConfig, userEntity);
|
|
|
} catch (Exception e) {
|