①初始化限购配置:限购方式配置,比如按用户id,客户端ip,收货人电话号等,配置限购时长,限购件数等;
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,
],
];
②设置限购商品数据内容,根据查询出来的商品信息,以及对应的活动信息进行判断。
1.处于活动中的商品判断限购,业务里根据商品或者活动层面的字段标识区分,例如秒杀活动,限时抢购,付邮试用等这些判断出是需要限购的商品,然后检验一下用户当前
购买件数是否超过指定值,作出异常处理。
这里先判断单sku是否超标,然后判断多sku和是否超标,这里需要在商品层面将spu商品标记出来,
if(isset(self::$checkProduct[$product['product_id']])){
self::$checkProduct[$product['product_id']] += $product['count'];
} else {
self::$checkProduct[$product['product_id']] = $product['count'];
}
符合的则记录限购商品的相关信息,供后续redis使用。
self::$productActivityBuyCountArr[$product['product_id'] . '_' . $product['sku_id']] = $product['count'];//当前sku的购买数量
$autoCacheInfo['tmp_limit_count'] = $activityLimitCount;
self::$productActivityTypeArr[$product['product_id'] . '_' . $product['sku_id']] = $autoCacheInfo; //限购商品信息
③商品检验完后,开始检查用户是否购买过,即判断是否超过已购买的限购次数,在redis存储数据进行判断和储存。
1.一种商品可能会陆续报名多个活动类型的限购,因此redis存储时标识的key应该区分开来,例如
$key = $value['productId'] . '_' . $value['activityId'];
$cacheKey = $keyword . $keyword_val . '_' . $key;
// user_id13432_7654_533或ip127.0.0.1_13432_533或phone15901438107_13432_533
2.根据对应的缓存key,incr指定的商品购买数量,并设置过期时间。然后检验incr后的结果与该商品限购数量进行比较,如果超过限购数量,则需要还原之前购买的次数的缓存,即将对应商品购买的数量还原减回去。
if (!empty(self::$_decr_key)) {
foreach (self::$_decr_key as $decrKey) {
CacheSDK::RedisDefault()->delBuyActivityProductRecord($decrKey, self::$_count);
if (isset(self::$_ActivityLimitItems[$productId][$decrKey])) {//回滚的时候去掉限制策略数据
unset(self::$_ActivityLimitItems[$productId][$decrKey]);
}
}
}
CacheSDK::RedisDefault()->delBuyActivityProductRecord($cheatKey, self::$_count);
//回滚的时候去掉限制策略数据
if (isset(self::$_ActivityLimitItems[$productId][$cheatKey])) {//回滚的时候去掉限制策略数据
unset(self::$_ActivityLimitItems[$productId][$cheatKey]);
}
(这块也是个bug,对于单商品多sku的购买,这里_ActivityLimitItems[cacheKey]```来获得相应的缓存key和对应商品spu的总数量,不用管self::$_decr_key )
如果可以购买,则记录当前商品的限购信息
private static $_decr_key = array(); //每次购买策略次数增加的key
array_push(self::$_decr_key, $cacheKey);
self::$_ActivityLimitItems[$productId][$cacheKey] = self::$_count; //添加被限制的策略数据,self::$_count为当前购买的数量才对
(这块应该是个bug,同一商品买多个sku情况下,商品数量应该累加的)
if(isset(self::$_ActivityLimitItems[$productId][$cacheKey])){
self::$_ActivityLimitItems[$productId][$cacheKey] += self::$_count;
}
④其他情况的失败,例如下单失败或者某个服务挂掉,用户取消订单等情况,之前限购的数据应该回滚,同样走上面的回滚逻辑,数据也是之前限购的数据内容(self::$productActivityTypeArr,做到按sku维度存储信息,然后按spu维度去统计限购,也就是循环多次想加的逻辑);取消订单的话,数据需要根据订单重新查询,然后拼接去redis中回滚。
⑤下单购买超出限购,抛出异常,提示已购买数量和限购总数,即还可以购买几件或者已购买完限购量。
网友评论