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的场景下,我们又该如何去解决并发. ...
随机推荐
- Spark以yarn方式运行时抛出异常
Spark以yarn方式运行时抛出异常: cluster.YarnClientSchedulerBackend: Yarn application has already exited with st ...
- iOS 开发之 开发一款自己的美颜相机
以前在公司做项目时很少遇到对相机.图片进行处理的(非公司业务),只是偶尔上传,裁剪,预览下.近期自己准备写个相机应用,把图片处理的这些技术细节整理下.包含美颜相机,图片美化,简单拼图,艺术拼图等主要模 ...
- 使用taglib指令在jsp页面导入要使用的jstl标签库
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
- IDEA中打war 包
把war 放入tomcat 的 webapps 目录下,重启tomcat即可自动解压war包跑起来 (最好是,解压完成后,关闭tomcat,把war包拷贝出去,再启动,不然每次启动tomcat都会自动 ...
- JAVA关于回文判断的实现
(一). 设计思想: 首先输入字符串,然后判断长度若长度为0或1则输出TRUE若长度大于一则进行判断, 若符合条件则输出TRUE反之输出FALSE. (二)程序源代码 import java.util ...
- Python学习笔记之基础篇(五)字典
#数据类型划分:可变数据类型 不可变数据类型 #不可变数据类型 : 元组 bool int str --> 可哈希 #可变数据类型 list ,dict set --->不可哈希 ''' ...
- PHP 三元运算符
$a = $a ? $a : 1;//第一种 $a = $a ? : 1;//第二种 第二种写法从 PHP 5.3 引入,表示若 $a 返回值为真时,取 $a 的返回值. 此外,在 PHP7 中引入了 ...
- ADV-299 宰羊 (java,过了30%)
问题描述 炫炫回了内蒙,肯定要吃羊肉啦,所有他家要宰羊吃. 炫炫家有N只羊,羊圈排成一排,标号1~N.炫炫每天吃掉一只羊(这食量!其实是放生啦),吃掉的羊的邻居会以为它被放生了,然后又会告诉他们的邻居 ...
- OpenCV数字识别
输入命令: conda install opencv 返回信息:
- java虚拟机之垃圾回收机制
一.需要回收的内存区域 程序计数器.虚拟机栈.本地方法栈 3 个区域随线程生灭(因为是线程私有),栈中的栈帧随着方法的进入和退出而有条不紊地执行着出栈和入栈操作.而 Java 堆和方法区则不一 ...