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悲观锁处理赠品库存超卖的情况的更多相关文章
- mysql处理高并发,防止库存超卖
先来就库存超卖的问题作描述:一般电子商务网站都会遇到如团购.秒杀.特价之类的活动,而这样的活动有一个共同的特点就是访问量激增.上千甚至上万人抢购一个商品.然而,作为活动商品,库存肯定是很有限的,如何控 ...
- Mysql在高并发情况下,防止库存超卖而小于0的解决方案
背景: 本人上次做申领campaign的PHP后台时,因为项目上线后某些时段同时申领的人过多,导致一些专柜的存货为负数(<0),还好并发量不是特别大,只存在于小部分专柜而且一般都是-1的状况,没 ...
- <转> mysql处理高并发,防止库存超卖
先来就库存超卖的问题作描述:一般电子商务网站都会遇到如团购.秒杀.特价之类的活动,而这样的活动有一个共同的特点就是访问量激增.上千甚至上万人抢购 一个商品.然而,作为活动商品,库存肯定是很有限的,如何 ...
- MYSQL处理高并发,防止库存超卖(图解)
抢购场景完全靠数据库来扛,压力是非常大的,我们在最近的一次抢购活动改版中,采用了redis队列+mysql事务控制的方案,画了个简单的流程图: 先来就库存超卖的问题作描述:一般电子商务网站都会遇到如团 ...
- mysql 悲观锁与乐观锁的理解
悲观锁与乐观锁是人们定义出来的概念,你可以理解为一种思想,是处理并发资源的常用手段. 不要把他们与mysql中提供的锁机制(表锁,行锁,排他锁,共享锁)混为一谈. 一.悲观锁 顾名思义,就是对于数据的 ...
- 记一次项目中解决 -- 并发减库存超卖问题过程(Java)
起因:项目中要做预约功能,首先每天的余票都是有上限的,自然不能出现超卖的情况 基于我们项目是单体分布式的springcloud部署,我想了下 第一种方法,直接mysql加行锁,要update这条库存数 ...
- 《MySQL悲观锁总结和实践》乐观锁
mysql乐观锁总结和实践 博客分类: MyBatis 数据库 mysql数据库乐观锁悲观锁 上一篇文章<MySQL悲观锁总结和实践>谈到了MySQL悲观锁,但是悲观锁并不是适用于任何场景 ...
- 【MySQL】MySQL悲观锁 + 事物 + for update 解决普通流量并发的问题
使用mysql悲观锁解决并发问题 最近学习了一下数据库的悲观锁和乐观锁,根据自己的理解和网上参考资料总结如下: 悲观锁介绍(百科): 悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事 ...
- 【分布式锁的演化】“超卖场景”,MySQL分布式锁篇
前言 之前的文章中通过电商场景中秒杀的例子和大家分享了单体架构中锁的使用方式,但是现在很多应用系统都是相当庞大的,很多应用系统都是微服务的架构体系,那么在这种跨jvm的场景下,我们又该如何去解决并发. ...
随机推荐
- 循环语句(for语句的用法)
for语句是最常用的循环语句,出现频率极高,多用于各种循环计算.具体的形式如下:for(表达式1;表达式2;表达式3) { 语句;}表达式1:用于初始化变量,变量既可以是全局也可以是局部变量, ...
- Android抓包分析-fiddler版
本文介绍的是如何使用Fiddler工具抓取Android应用的HTTP协议的数据包 工具 Genymotion模拟器 笔记本电脑一台(Win7) Fiddler(v4.6.2),下载地址:http:/ ...
- ubuntu13.10更新sources.list
步骤: 1>设置网络连接方式,NAT 2>自动获取ip address 10.0.2.15 3>更新源soureces.list soureces.list deb http://m ...
- java中如何修改事务的隔离级别
事务的特性: 原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生. (多条语句要么都成功,要么都失败.) 一致性(Consistency)事务前后 ...
- Django 学习 之路由层(URL)
路由层(URL) 1.路由层简单配置 (1)path方法 写固定的url. (2)re_path方法 可以正则规则 例: urlpatterns = [ path('admin/', admin.si ...
- MySQL操作之DCL
目录 SQL语句的分类 DCL语句 SQL语句的分类 DDL(Data Definition Languages)语句:数据定义语言.这些语句定义了不同的数据段. 数据库.表.列.索引等数据库对象的定 ...
- 新建Django 项目完整流程
1) 在桌面或者其他文件 新建项目名称 (mkdir 新建文件夹) 2)进入文件夹 pipenv --python3(用命令提示粘贴复制, 自己这样写经常有问题) 3) 启动虚拟环境 pipenv ...
- token和session的区别
session和token都是用来保持会话,功能相同 一.session机制,原理 session是服务端存储的一个对象,主要用来存储所有访问过该服务端的客户端的用户信息(也可以存储其他信息),从而实 ...
- mysql 通过localhost可以连接IP连接不上
因为MySQL默认没开 所以需要手动设置 开MySQL启远程连接的功能,在MySQL服务器控制台上执行以下命令: 设置权限: grant all privileges on *.* to 用户名@&q ...
- js判断数组中是否包含某个元素
参考:http://www.runoob.com/jquery/misc-inarray.html js判断数组中是否包含某个元素 $.inArray( value, array [, fromInd ...