码迷,mamicode.com
首页 > 数据库 > 详细

mysql悲观锁处理赠品库存超卖的情况

时间:2018-05-27 16:17:37      阅读:237      评论:0      收藏:0      [点我收藏+]

标签:reac   比较   HERE   9.png   ror   html   测试的   round   了解   

处理库存超卖的情况前,先了解下什么是乐观锁和悲观锁,下面的几篇博客已经介绍的比较详细了,我就不在赘述其原理了

【MySQL】悲观锁&乐观锁

 

对mysql乐观锁、悲观锁、共享锁、排它锁、行锁、表锁概念的理解

 

下面开始介绍悲观锁在实际中的应用了

//下订单

..........
try {
M()->startTrans();

//
判断商品是否有赠品 $give_gift=$ob->getGiveGoods($sku_nos); if(!empty($give_gift)){ $this->dealSkuGift($give_gift,$ob,$data[order_no],$skuNumArr,$packageSku); }
}catch(FlException $ex) {
M()->rollback();
$curCode = $ex->getErrorCode();
$curmsg = $ex->getMessage();
E($curCode, $curmsg);
}
M()->commit();

..........

//获取赠品库存

public function getGiveGoodsStock($sku_no){
    $sku_no=implode(",",array_unique($sku_no));
    $sku_no = "".str_replace(",","‘,‘",$sku_no)."";
    $Model = new \Think\Model();
    $sku_gift_info=$Model->query("select sku_no,stock from ".C(DB_PREFIX)."sku_gift_stock where is_deleted=0 and is_online=1 and sku_no in($sku_no) for update");
    return $sku_gift_info;
}

// 处理赠品

private function dealSkuGift($give_gift,$ob,$orderNo,$skuNumArr,$packageSku){
    if(empty($give_gift) or empty($skuNumArr)){
         return false;
    }
    $skuGiftStockM=M(sku_gift_stock);
    $sku_gifts=array_column($give_gift,sku_no);
    //获取赠品库存
    $sku_give_gift=$ob->getGiveGoodsStock($sku_gifts,1);
    $skuGiftStock=array();
    $giftCount=0;
    foreach($sku_give_gift as $k=>$v){
         $skuGiftStock[$v[sku_no]]=$v[stock];
    }
    $public = new PModel();
    foreach ($give_gift as $v){
         $goodsNums=0;
         $delStockWhere=array();
         if($v[isHaveStock]==1 && $skuGiftStock[$v[sku_no]] >0){//代表有货--这些是需要发货的
              if($v[type]==1){
                  $lastGiftNum=$skuNumArr[$v[parent_sku_no]]*$v[goods_nums];
              }else{//按固定赠品数量
                  $lastGiftNum=$v[goods_nums];
              }
              if($lastGiftNum >= $v[stock_num]){
                  $lastGiftNum=$v[stock_num];
              }
              if($v[stock_num]==0){
                  $lastGiftNum=0;
              }
              $delStockWhere[sku_no]=$v[sku_no];
              $delStockWhere[is_deleted]=0;
              $delStockWhere[is_online]=1;
              $delStockWhere[‘_string‘]= sprintf(‘stock>=%d‘, $lastGiftNum);
              $skuGiftStockM->where($delStockWhere)->lock(true)->setDec(stock,$lastGiftNum);//扣除商品赠品库存
              $re_v=$public->updataSignData($v[sku_no],$lastGiftNum,virtual_inventory,-,goods_sku,sku_no);//扣除赠品商品库存
              if(false == $re_v){
                    E(300110);
              }
              $giftCount+=$lastGiftNum;
         }else{
              $lastGiftNum=0;
         }
         $dd[]=array(
              parent_sku_no=>$v[parent_sku_no],
              sku_no=>$v[sku_no],
              num=>$lastGiftNum,//最终发货的数量,无货为0
              create_time=>date(Y-m-d H:i:s,time()),
              order_no=>$orderNo,
              package_id=>$packageSku[$v[parent_sku_no]],
              stock_num=>empty($skuGiftStock[$v[sku_no]])?0:$skuGiftStock[$v[sku_no]]
         );
    }
    $order_goods_gift=M(order_goods_gift);
    $order_goods_gift->addAll($dd);

    $upOrdeData=array(
         gift_count=>$giftCount+1
    );
    M(order)->where(order_no=".$orderNo.")->data($upOrdeData)->save();
    return true;
}

//接口访问方式

技术分享图片

//由于要测试并发下该接口的超卖处理情况,所以访问接口前,可将body里的参数写死到接口内,这样方便调试

技术分享图片

//再次访问接口

技术分享图片

//下面就可以用apache的ab工具对下单接口进行并发测试了

技术分享图片

技术分享图片

 到数据库里查看商品P002026-01关联了2个赠品,各关联了10个

技术分享图片

查看赠品的库存数量

技术分享图片

技术分享图片

apache并发测试的原理及使用方法参见博客:https://www.cnblogs.com/lishuyi/p/5808661.html

使用方法:

ab -n 10 -c 5  http://app.zouke.com/ 
(-n发出10个请求,-c模拟5个并发,相当5人同时访问,后面是测试url)

ab -t 60 -c 100 http://192.168.0.10/ 
在60秒内发请求,一次100个请求。 

先预测下,请求10次,并发5个,最终的库存会剩余0

下面开始并发测试

技术分享图片

最终赠品P002872、P002962的剩余库存如下

技术分享图片

技术分享图片

结果可见,本次悲观锁起了效果,下面看下不用悲观锁的情况会是什么样,下面将2个赠品的库存都恢复为10个,并将获取赠品库存代码进行改造,这次获取赠品库存是没加悲观锁的

//获取赠品库存
public function getGiveGoodsStock($sku_no,$ori){
    $sku_gift=M(sku_gift_stock);
    $sgg_where[sku_no]=array(in,$sku_no);
    $sgg_where[is_deleted]=0;
    $sgg_where[is_online]=1;
    $sku_gift_info=$sku_gift->field(sku_no,stock)->where($sgg_where)->select();
    return $sku_gift_info;
}

再次并发测试一下

技术分享图片

发现赠品库存是变为负数了,这是超卖的情况出现了

技术分享图片

好了,以上测试可以了,下面看下直接用操作数据表看下效果,按如下顺序执行,发现当执行完前4步后,用户B查询不到赠品库存信息,主要是因为此时赠品表已经锁住了

技术分享图片

下面执行用户A第5步COMMIT,用户B查询赠品库存立马查询出来了

技术分享图片

上述可见,mysql悲观锁对赠品库存超卖的处理流程的生效过程了

 

mysql悲观锁处理赠品库存超卖的情况

标签:reac   比较   HERE   9.png   ror   html   测试的   round   了解   

原文地址:https://www.cnblogs.com/zouke1220/p/9096077.html

(0)
(1)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!