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的场景下,我们又该如何去解决并发. ...
随机推荐
- vue学习笔记:数据渲染操作
{{xxx}} 基本的插值表达式 插值表达式 使用两个大括号 {{ data中定义的数据名 }} 可以将数据插入到指定的位置 这种写法不仅可以显示data属性里定义的值,也可以书写js中的表达式,可以 ...
- SSD boot test script for(if)循环
;Author : Bing Song ;// ;Usage: modify log drictory according to actual drictory gettime timestr &qu ...
- Linux 7 和 CentOS 7 收到重要内核安全更新
导读 Red Hat 和 CentOS 宣布了其 Red Hat Enterprise Linux 7 和 CentOS Linux 7 操作系统系列重要内核安全更新的可用性. 据悉,这些更新解决了两 ...
- TensorFlow样例一
假设原函数为 f(x) = 5x^2 + 3,为了估计出这个函数,定义参数未知的函数g(x, w) = w0 x^2 + w1 x + w2,现要找出适合的w使g(x, w) ≍ f(x).将这个问题 ...
- Spark入门:第4节 Spark程序:1 - 9
五. Spark角色介绍 Spark是基于内存计算的大数据并行计算框架.因为其基于内存计算,比Hadoop中MapReduce计算框架具有更高的实时性,同时保证了高效容错性和可伸缩性.从2009年诞生 ...
- 【PAT甲级】1005 Spell It Right (20 分)
题意: 给出一个非零整数N(<=10^100),计算每位之和并用英文输出. AAAAAccepted code: #include<bits/stdc++.h> using name ...
- 38 java 使用标签跳出多层嵌套循环
public class Interview { public static void main(String[] args) { //使用带标签的break跳出多层嵌套循环 Boolean flag ...
- 单元测试报错:unable to find a @SpringBootConfiguration
完整异常: Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBoo ...
- 输出简单图形(StringBuilder代替双重循环)
在有些题目中打印简单图形必须使用StringBuilder或者StringBuffer,否则会运行超时(用String都会超时). 因为在题目的要求中说到输入的n是小于1000的,用双重循环就会超时, ...
- 设计模式课程 设计模式精讲 19-2 策略模式coding
1 代码演练 1.1 代码演练1(多态) 1.2 代码演练2(优化应用) 1.3 代码演练3(策略模式结合工厂模式) 1 代码演练 1.1 代码演练1(多态) 需求: 木木网卖课程,为了促进销售,61 ...