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

【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,);
$skuGiftStock=array();
$giftCount=;
foreach($sku_give_gift as $k=>$v){
$skuGiftStock[$v['sku_no']]=$v['stock'];
}
$public = new PModel();
foreach ($give_gift as $v){
$goodsNums=;
$delStockWhere=array();
if($v['isHaveStock']=='' && $skuGiftStock[$v['sku_no']] >){//代表有货--这些是需要发货的
if($v['type']==''){
$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']==){
$lastGiftNum=;
}
$delStockWhere['sku_no']=$v['sku_no'];
$delStockWhere['is_deleted']=;
$delStockWhere['is_online']=;
$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('');
}
$giftCount+=$lastGiftNum;
}else{
$lastGiftNum=;
}
$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']])?:$skuGiftStock[$v['sku_no']]
);
}
$order_goods_gift=M('order_goods_gift');
$order_goods_gift->addAll($dd); $upOrdeData=array(
'gift_count'=>$giftCount+
);
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 1 -c   http://app.zouke.com/
(-n发出10个请求,-c模拟5个并发,相当5人同时访问,后面是测试url) ab -t -c 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']=;
$sgg_where['is_online']=;
$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悲观锁处理赠品库存超卖的情况的更多相关文章

  1. mysql处理高并发,防止库存超卖

    先来就库存超卖的问题作描述:一般电子商务网站都会遇到如团购.秒杀.特价之类的活动,而这样的活动有一个共同的特点就是访问量激增.上千甚至上万人抢购一个商品.然而,作为活动商品,库存肯定是很有限的,如何控 ...

  2. Mysql在高并发情况下,防止库存超卖而小于0的解决方案

    背景: 本人上次做申领campaign的PHP后台时,因为项目上线后某些时段同时申领的人过多,导致一些专柜的存货为负数(<0),还好并发量不是特别大,只存在于小部分专柜而且一般都是-1的状况,没 ...

  3. <转> mysql处理高并发,防止库存超卖

    先来就库存超卖的问题作描述:一般电子商务网站都会遇到如团购.秒杀.特价之类的活动,而这样的活动有一个共同的特点就是访问量激增.上千甚至上万人抢购 一个商品.然而,作为活动商品,库存肯定是很有限的,如何 ...

  4. MYSQL处理高并发,防止库存超卖(图解)

    抢购场景完全靠数据库来扛,压力是非常大的,我们在最近的一次抢购活动改版中,采用了redis队列+mysql事务控制的方案,画了个简单的流程图: 先来就库存超卖的问题作描述:一般电子商务网站都会遇到如团 ...

  5. mysql 悲观锁与乐观锁的理解

    悲观锁与乐观锁是人们定义出来的概念,你可以理解为一种思想,是处理并发资源的常用手段. 不要把他们与mysql中提供的锁机制(表锁,行锁,排他锁,共享锁)混为一谈. 一.悲观锁 顾名思义,就是对于数据的 ...

  6. 记一次项目中解决 -- 并发减库存超卖问题过程(Java)

    起因:项目中要做预约功能,首先每天的余票都是有上限的,自然不能出现超卖的情况 基于我们项目是单体分布式的springcloud部署,我想了下 第一种方法,直接mysql加行锁,要update这条库存数 ...

  7. 《MySQL悲观锁总结和实践》乐观锁

    mysql乐观锁总结和实践 博客分类: MyBatis 数据库 mysql数据库乐观锁悲观锁 上一篇文章<MySQL悲观锁总结和实践>谈到了MySQL悲观锁,但是悲观锁并不是适用于任何场景 ...

  8. 【MySQL】MySQL悲观锁 + 事物 + for update 解决普通流量并发的问题

    使用mysql悲观锁解决并发问题   最近学习了一下数据库的悲观锁和乐观锁,根据自己的理解和网上参考资料总结如下: 悲观锁介绍(百科): 悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事 ...

  9. 【分布式锁的演化】“超卖场景”,MySQL分布式锁篇

    前言 之前的文章中通过电商场景中秒杀的例子和大家分享了单体架构中锁的使用方式,但是现在很多应用系统都是相当庞大的,很多应用系统都是微服务的架构体系,那么在这种跨jvm的场景下,我们又该如何去解决并发. ...

随机推荐

  1. spring security几大核心组件

    一.SecurityContext 安全上下文,用户通过Spring Security 的校验之后,验证信息存储在SecurityContext中 SecurityContext接口只定义了两个方法, ...

  2. Lesson 16 The modern city

    What is the author's main argument about the modern city? In the organization of industrial life the ...

  3. Tomcat认识

    Tomcat目录结构: bin:存放启动和关闭的一些脚本 common:共享(部署在该服务器上的一些)jar包 conf:存放服务器的一些配置文件 webapps:部署文件 work:服务器运行时,产 ...

  4. ubuntu13.10安装tomcat

    步骤: ubuntu :13.10(32bit) -->i586 jdk 1.7 安装JDK 步骤: 1.官网下载如下图: 2.点击java SE7,下载jdk1.7 3.点击接受,并下载对应的 ...

  5. Mybatis plus 插入数据时将自动递增的主键手动进行赋值设置

    1.首先设置好实体类:将类型设置为 @TableId(type = IdType.INPUT) 2.在插入数据前将id赋值给实体类对象即可

  6. 3_07_MSSQL课程_Ado.Net_委托、事件

    委托和事件的区别? (1)委托是一个类. 事件是一个委托类型的实列. (2)委托可以在定义委托实列的类的外部触发执行.(不安全) 事件只能能在定义它的类的内部触发执行.(安全),类外部只能注册事件的响 ...

  7. tensorflow中的Fetch、Feed(02-3)

    import tensorflow as tf #Fetch概念 在session中同时运行多个op input1=tf.constant(3.0) #constant()是常量不用进行init初始化 ...

  8. 8个问题全面了解5G关键技术Massive MIMO

    1 什么是Massive MIMO Massive MIMO(大规模天线技术,亦称为Large Scale MIMO)是第五代移动通信(5G)中提高系统容量和频谱利用率的关键技术.它最早由美国贝尔实验 ...

  9. vector的clear和swap

    vector的clear()操作只是清空vector的元素,而不会将内存释放掉 vector<int> vec1{ 1,2,3,4,5 }; vec1.clear(); cout<& ...

  10. Controller生命周期

    1. 实例化 alloc/init, initWithNibName 2.awakeFromNib 从nib创建Controller对象 3.get/set outlets 4. viewDidLoa ...