①初始化限購配置:限購方式配置畅铭,比如按用戶id菠隆,客戶端ip兵琳,收貨人電話號等,配置限購時長骇径,限購件數(shù)等;
self::$_cache_strategy_config = [
"ip" => ["time" => 86400 * 15, "limit" => 1],
"user_id" => ["time" => 86400 * 15, "limit" => 1],
"delivery_mobilephone" => ["time" => 86400 * 15, "limit" => 1],
"imei" => ["time" => 86400 * 15, "limit" => 1],
];
然后是活動類型的限購躯肌,比如秒殺活動的商品限購1件,搶購活動的商品限購5件等破衔。
self::$_cache_strategy_config_factor = [
"MS" => [
"ip" => 10,
"user_id" => 1,
"delivery_mobilephone" => 1,
],
"QG" => [
"ip" => 10,
"user_id" => 1,
"delivery_mobilephone" => 1,
],
];
②設(shè)置限購商品數(shù)據(jù)內(nèi)容清女,根據(jù)查詢出來的商品信息,以及對應(yīng)的活動信息進(jìn)行判斷晰筛。
1.處于活動中的商品判斷限購嫡丙,業(yè)務(wù)里根據(jù)商品或者活動層面的字段標(biāo)識區(qū)分拴袭,例如秒殺活動,限時搶購曙博,付郵試用等這些判斷出是需要限購的商品拥刻,然后檢驗一下用戶當(dāng)前
購買件數(shù)是否超過指定值,作出異常處理父泳。
這里先判斷單sku是否超標(biāo)泰佳,然后判斷多sku和是否超標(biāo),這里需要在商品層面將spu商品標(biāo)記出來尘吗,
if(isset(self::$checkProduct[$product['product_id']])){
self::$checkProduct[$product['product_id']] += $product['count'];
} else {
self::$checkProduct[$product['product_id']] = $product['count'];
}
符合的則記錄限購商品的相關(guān)信息逝她,供后續(xù)redis使用。
self::$productActivityBuyCountArr[$product['product_id'] . '_' . $product['sku_id']] = $product['count'];//當(dāng)前sku的購買數(shù)量
$autoCacheInfo['tmp_limit_count'] = $activityLimitCount;
self::$productActivityTypeArr[$product['product_id'] . '_' . $product['sku_id']] = $autoCacheInfo; //限購商品信息
③商品檢驗完后睬捶,開始檢查用戶是否購買過黔宛,即判斷是否超過已購買的限購次數(shù),在redis存儲數(shù)據(jù)進(jìn)行判斷和儲存擒贸。
1.一種商品可能會陸續(xù)報名多個活動類型的限購臀晃,因此redis存儲時標(biāo)識的key應(yīng)該區(qū)分開來,例如
$key = $value['productId'] . '_' . $value['activityId'];
$cacheKey = $keyword . $keyword_val . '_' . $key;
// user_id13432_7654_533或ip127.0.0.1_13432_533或phone15901438107_13432_533
2.根據(jù)對應(yīng)的緩存key介劫,incr指定的商品購買數(shù)量徽惋,并設(shè)置過期時間。然后檢驗incr后的結(jié)果與該商品限購數(shù)量進(jìn)行比較座韵,如果超過限購數(shù)量险绘,則需要還原之前購買的次數(shù)的緩存,即將對應(yīng)商品購買的數(shù)量還原減回去。
if (!empty(self::$_decr_key)) {
foreach (self::$_decr_key as $decrKey) {
CacheSDK::RedisDefault()->delBuyActivityProductRecord($decrKey, self::$_count);
if (isset(self::$_ActivityLimitItems[$productId][$decrKey])) {//回滾的時候去掉限制策略數(shù)據(jù)
unset(self::$_ActivityLimitItems[$productId][$decrKey]);
}
}
}
CacheSDK::RedisDefault()->delBuyActivityProductRecord($cheatKey, self::$_count);
//回滾的時候去掉限制策略數(shù)據(jù)
if (isset(self::$_ActivityLimitItems[$productId][$cheatKey])) {//回滾的時候去掉限制策略數(shù)據(jù)
unset(self::$_ActivityLimitItems[$productId][$cheatKey]);
}
(這塊也是個bug誉碴,對于單商品多sku的購買宦棺,這里_ActivityLimitItems[
cacheKey]```來獲得相應(yīng)的緩存key和對應(yīng)商品spu的總數(shù)量黔帕,不用管self::$_decr_key )
如果可以購買代咸,則記錄當(dāng)前商品的限購信息
private static $_decr_key = array(); //每次購買策略次數(shù)增加的key
array_push(self::$_decr_key, $cacheKey);
self::$_ActivityLimitItems[$productId][$cacheKey] = self::$_count; //添加被限制的策略數(shù)據(jù),self::$_count為當(dāng)前購買的數(shù)量才對
(這塊應(yīng)該是個bug,同一商品買多個sku情況下成黄,商品數(shù)量應(yīng)該累加的)
if(isset(self::$_ActivityLimitItems[$productId][$cacheKey])){
self::$_ActivityLimitItems[$productId][$cacheKey] += self::$_count;
}
④其他情況的失敗呐芥,例如下單失敗或者某個服務(wù)掛掉,用戶取消訂單等情況奋岁,之前限購的數(shù)據(jù)應(yīng)該回滾思瘟,同樣走上面的回滾邏輯,數(shù)據(jù)也是之前限購的數(shù)據(jù)內(nèi)容(self::$productActivityTypeArr厦取,做到按sku維度存儲信息潮太,然后按spu維度去統(tǒng)計限購,也就是循環(huán)多次想加的邏輯);取消訂單的話铡买,數(shù)據(jù)需要根據(jù)訂單重新查詢更鲁,然后拼接去redis中回滾。
⑤下單購買超出限購奇钞,拋出異常澡为,提示已購買數(shù)量和限購總數(shù),即還可以購買幾件或者已購買完限購量景埃。