param('order_type', ''); $order_type = $order_type ?: 'goods'; // 普通商品销量处理 (积分和普通商品的缓存 key 不相同) $keyGoodsLockedNum = $this->getLockedGoodsKey($buyInfo['goods_id'], $buyInfo['goods_sku_price_id'], $order_type); $locked_num = redis_cache($keyGoodsLockedNum); if ($order_type == 'score') { // 验证积分商品库存是否充足(mysql 悲观锁,此方法可靠,但如果大规模秒杀,容易mysql 死锁,请将商品添加为秒杀) $stock = ScoreSkuPrice::where('goods_id', $buyInfo['goods_id'])->where('goods_sku_price_id', $buyInfo['current_sku_price']->id)->lock(true)->value('stock'); if (($stock - $locked_num) < $buyInfo['goods_num']) { error_stop('积分商品库存不足'); } } // 验证商品库存是否充足(mysql 悲观锁,此方法可靠,但如果大规模秒杀,容易mysql 死锁,请将商品添加为秒杀) $stock = SkuPrice::where('id', $buyInfo['current_sku_price']->id)->lock(true)->value('stock'); if (($stock - $locked_num) < $buyInfo['goods_num']) { error_stop('商品库存不足'); } // 锁库存 redis_cache()->INCRBY($keyGoodsLockedNum, $buyInfo['goods_num']); } public function stockUnLock($order) { $items = $order->items; foreach ($items as $key => $item) { $this->stockUnLockItem($item); } } public function stockUnLockItem($item) { $keyGoodsLockedNum = $this->getLockedGoodsKey($item['goods_id'], $item['goods_sku_price_id']); $locked_num = redis_cache()->DECRBY($keyGoodsLockedNum, $item->goods_num); if ($locked_num < 0) { $locked_num = redis_cache()->set($keyGoodsLockedNum, 0); } } // 真实正向 减库存加销量(支付成功扣库存,加销量) public function forwardStockSale($order) { $items = OrderItem::where('order_id', $order['id'])->select(); foreach ($items as $key => $item) { // 增加商品销量 Goods::where('id', $item->goods_id)->setInc('sales', $item->goods_num); $skuPrice = SkuPrice::where('id', $item->goods_sku_price_id)->find(); if ($skuPrice) { SkuPrice::where('id', $item->goods_sku_price_id)->setDec('stock', $item->goods_num); // 减少库存 SkuPrice::where('id', $item->goods_sku_price_id)->setInc('sales', $item->goods_num); // 增加销量 // 库存预警检测 $this->checkStockWarning($skuPrice); } if ($item->item_goods_sku_price_id) { if ($order['type'] == 'score') { // 积分商城商品,扣除积分规格库存 ScoreSkuPrice::where('id', $item->item_goods_sku_price_id)->setDec('stock', $item->goods_num); // 减少库存 ScoreSkuPrice::where('id', $item->item_goods_sku_price_id)->setInc('sales', $item->goods_num); } else { // 扣除活动库存 ActivitySkuPriceModel::where('id', $item->item_goods_sku_price_id)->setDec('stock', $item->goods_num); // 减少库存 ActivitySkuPriceModel::where('id', $item->item_goods_sku_price_id)->setInc('sales', $item->goods_num); } } // 真实库存已减,库存解锁(非活动) if (!$item['activity_id']) { $this->stockUnLockItem($item); } } } // 真实反向 加库存减销量(订单退全款) public function backStockSale($order, $items = []) { if (!$items) { $items = OrderItem::where('order_id', $order['id'])->select(); } foreach ($items as $key => $item) { // 返还商品销量 Goods::where('id', $item->goods_id)->setDec('sales', $item->goods_num); // 返还规格库存 $skuPrice = SkuPrice::where('id', $item->goods_sku_price_id)->find(); if ($skuPrice) { SkuPrice::where('id', $item->goods_sku_price_id)->setInc('stock', $item->goods_num); // 返还库存 SkuPrice::where('id', $item->goods_sku_price_id)->setDec('sales', $item->goods_num); // 减少销量 // 库存预警检测 $this->checkStockWarning($skuPrice); } if ($item->item_goods_sku_price_id) { if ($order['type'] == 'score') { // 积分商城商品,扣除积分规格库存 ScoreSkuPrice::where('id', $item->item_goods_sku_price_id)->setInc('stock', $item->goods_num); // 返还库存 ScoreSkuPrice::where('id', $item->item_goods_sku_price_id)->setDec('sales', $item->goods_num); // 减少销量 } else { // 扣除活动库存 ActivitySkuPriceModel::where('id', $item->item_goods_sku_price_id)->setInc('stock', $item->goods_num); // 返还库存 ActivitySkuPriceModel::where('id', $item->item_goods_sku_price_id)->setDec('sales', $item->goods_num); // 减少销量 } } } } // cache 正向加销量,添加订单之前拦截 public function cacheForwardSale($buyInfo) { $goods = $buyInfo['goods']; $activity = $goods['activity']; if (has_redis()) { $keys = ActivityRedisFacade::keysActivity([ 'goods_id' => $goods->id, 'goods_sku_price_id' => $buyInfo['current_sku_price']->id, ], [ 'activity_id' => $activity['id'], 'activity_type' => $activity['type'], ]); extract($keys); // 活动商品规格 $goodsSkuPrice = Redis::HGET($keyActivity, $keyGoodsSkuPrice); $goodsSkuPrice = json_decode($goodsSkuPrice, true); // 活动商品库存 $stock = $goodsSkuPrice['stock'] ?? 0; // 当前销量 + 购买数量 ,salekey 如果不存在,自动创建 $sale = Redis::HINCRBY($keyActivity, $keySale, $buyInfo['goods_num']); if ($sale > $stock) { $sale = Redis::HINCRBY($keyActivity, $keySale, -$buyInfo['goods_num']); error_stop('活动商品库存不足'); } } } // cache 反向减销量,取消订单/订单自动关闭 时候 public function cacheBackSale($order) { $items = OrderItem::where('order_id', $order['id'])->select(); foreach ($items as $key => $item) { $this->cacheBackSaleByItem($item); } } // 通过 OrderItem 减预库存 private function cacheBackSaleByItem($item) { if (has_redis()) { $keys = ActivityRedisFacade::keysActivity([ 'goods_id' => $item['goods_id'], 'goods_sku_price_id' => $item['goods_sku_price_id'], ], [ 'activity_id' => $item['activity_id'], 'activity_type' => $item['activity_type'], ]); extract($keys); if (Redis::EXISTS($keyActivity) && Redis::HEXISTS($keyActivity, $keySale)) { $sale = Redis::HINCRBY($keyActivity, $keySale, -$item['goods_num']); } return true; } } /** * 获取库存锁定 key * * @param int $goods_id * @param int $goods_sku_price_id * @return string */ private function getLockedGoodsKey($goods_id, $goods_sku_price_id, $order_type = 'goods') { $prefix = 'locked_goods_num:' . $order_type . ':' . $goods_id . ':' . $goods_sku_price_id; return $prefix; } }