版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
php结合redis实现高并发下的抢购、秒杀功能抢购、秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个:1高并发对数据库产生的压力2竞争状态下如何解决库存的正确减少("超卖"问题)对于第一个问题,已经很容易想到用缓存来处理抢购,避免直接操作数据库,例如使用RediSo重点在于第二个问题常规写法:查询出对应商品的库存,看是否大于0,然后执行生成订单等操作,但是在判断库存是否大于0处,如果在高并发下就会有问题,导致库存量出现负数1<!--?php$conn=mysql_connect("localhost"/'big"/'123456");if(!$conn){echo"connectfailed";exit;}mysql_select_db("big",$conn);mysql_query("setnamesutf8");9$price=10;1$user_id=l;$goods_id=l;13$sku_id=ll;$number=l;1516〃生成唯一订单functionbuild__order_no(){returndate('ymd').substr(implode(NULL,array_map('ord',str_split(substr(uniqid(),7,13),1))),0,8);20)21〃记录日志functioninsertLog($event,$type=0){global$conn;$sql="insertintoih_log(event,type)values('$event'J$type')*';
mysql_query($sql,$conn);27}2829〃模拟卜单操作30〃库存是否大于0$sql=Hselectnumberfromih_storewheregoods_id='$goods_id'andsku_id='$sku_id'〃解锁此时ih_store数据中goods_id='$goods_id'and33sku_id—$sku_iL的数据被锁住(注3),其它事务必须等待此次事务提交后才能执34行$rs=mysql_query($sql,$conn);$row=mysql_fetch_assoc($rs);37if($row['numbeZ]—>0){〃高并发下会导致超卖$order_sn=build_order_no();39〃生成订单$sql=Minsertintoih_order(order_sn,use^id^goods-id^sku_idjprice)values(*$order_sn','$user_id*J$goods_id','$sku__id','$price'43$order_rs=mysql_query($sqlJ$conn);4546〃库存减少$sql=*'updateih_storesetnumber=number-{$number}where4sku_id='$sku_id*";$store_rs=mysql_query($sqlJ$conn);if(mysql_affected_rows()){insertLog(,库存减少成功');}else(insertLog(,库存减少失败');)}else{insertLog(,库存不够‘);)?>优化方案L将库存字段number字段设为unsigned,当库存为0时,因为字段不能为负数,将会返回false1〃库存减少$sql=Hupdateih_storesetnumber=number-{$number}wheresku_id='$sku_idandnumber)。”;$store_rs=mysql_query($sqlJ$conn);if(mysql_affected_rows()){insertLog(,库存减少成功');)优化方案2:使用mysql的事务,锁住操作的行1<!--?php$conn=mysql_connect(,,localhostM/,bigMJM123456n);if(!$conn){echo"connectfailed";exit;6)mysql_select_db("big",$conn);mysql_query("setnamesutf8");9$price=10;$user_id=l;$goods_id=l;$sku_id=ll;$number=l;1516//生成唯一订单号1functionbuild_order_no(){returndate('ymd').substr(implode(NULL,array__map('ord',str_split(substr(uniqid()7,13),1))),0,8);20)21//记录日志functioninsertLog($event>$type=0){global$conn;$sql="insertintoih__log(eventstype)values('$event','$type';mysql_query($sql,$conn);27}2829〃模拟下单操作30〃库存是否大于0;mysql_query("BEGIN"); 〃开始事务$sql="selectnumberfromih__storewheregoods__id='$goods__id'and3sku_id='$sku_id*FORUPDATE”;〃此时这条记录被锁住,其它事务必须等待此次事务34提交后才能执行$rs=mysql_query($sqlJ$conn);$row=mysql_fetch_assoc($rs);7if($row['number']-->0){38〃生成订单$order_sn=build_order_no();$sql="insertintoih_order(order__snJuser_idJgoods_idJsku-id^price)values('$order_sn*,'$user_id','$goods_id'J$sku_id'J$price')";$order__rs=mysql_query($sqlJ$conn);4344〃库存减少$sql="updateih_storesetnumber=number-{$number}where46sku_id='$sku_id,n;$store_rs=mysql_query($sqlJ$conn);if(mysql_affected_rows()){insertLog('库存减少成功');mysql_query("COMMIT");〃事务提交即解锁}else(insertLog(,库存减少失败’);)}else{insertLog(1库存不够,);mysql__query("ROLLBACK");优化方案3:使用非阻塞的文件排他锁1<!--?php$conn=mysql_connect(,,localhost"/,root"/,123456n);3if(!$conn){echo"connectfailed";exit;6}mysql_select_db("big-bak'\$conn);mysql_query("setnamesutf8");9$price=10;$user_id=l;$goods_id=l;$sku_id=ll;$number=l;1516〃生成唯一订单号1/functionbuild_order_no(){returndate('ymd').substr(implode(NULL,array__map('ord',str_split(substr(uniqid()7,13),1))),0,8);20)21〃记录日志functioninsertLog($event>$type=0){global$conn;$sql="insertintoih__log(eventstype)values('$event'J$type')u;mysql_query($sqlj$conn);}282$fp=fopenC'lock.txt","w+H);if(!flock($fp,LOCK_EX|LOCK_NB)){echo”系统繁忙,请稍后再试二return;33}34〃下单$sql=Hselectnumberfromih_storewheregoods_id='$goods_id'and3sku_id='$sku_id'n;$rs=mysql__query($sql,$conn);$row=mysql_fetch_assoc($rs);if($row['number' {〃库存是否大于040 〃模拟下单操作$order__sn=build_order_no();$sql=Hinsertintoih_order(order_sn,user_idJgoods_idJsku_id,price)values(*$order_sn','$user_id*,'$goods_id','$sku__id'J$price*$order_rs=mysql_query($sqlJ$conn);4546〃库存减少$sql="updateih_storesetnumber=number-{$number}where4sku_id='$sku_id'";$store_rs=mysql__query($sql>$conn);if(mysql_affected_rows()){insertLog('库存减少成功’);flock($fp,LOCK_UN);〃释放锁}else(insertLog(,库存减少失败');55 )56}else{insertLog(,库存不够‘);)fclose($fp);优化方案4:使用redis队列,因为pop操作是原子的,即使有很多用户同时到达,也是依次执行,推荐使用(mysql事务在高并发下性能下降很厉害,文件锁的方式也是)先将商品库存如队列1<!--?php$store=1000;$redis=newRedis();$result=$redis——>connect(''16379);$res=$redis->llen('goods_store');echo$res;
$count=$store-$res;for($i=0;$i<$count;$i++){$redis->lpush('goods_store',1);10}echo$redis->llen('goods_store');12?>2324252324252627)28}3839//生成订单$order_sn=build_order_no();$sql="insertintoih_order(order_sn,user_id,goods_id,sku_id,price)42values('$order_sn','$user_id\'$goods_id','$sku_id','$price')K;$order_rs=mysql_query($sql>$conn);4445〃库存减少$sql="updateih_storesetnumber=number-{$number}wheresku_id='$sku_id'$store_rs=mysql_query($sql,$conn);if(mysql_affected_rows()){insertLog(,库存减少成功,);51}else(insertLog(,库存减少失败,);)模拟5000高并发测试webbench-c5000-t60/big/index.phpab-r-n6000-c5000/big/index.php上述只是简单模拟高并发下的抢购,真实场景要比这复杂很多,很多注意的地方如抢购页面做成静态的,通过ajax调用接口再如上面的会导致一个用户抢多个,思路:需要一个排队队列和抢购结果队列及库存队列。高并发情况,先将用户进入排队队列,用一个线程循环处理从排队队列取出一个用户,判断用户是否已在抢购结果队列,如果在,则已抢购,否则未抢购,库存减1,写数据库,将用户入结果队列。测试数据表1--2--数据库:'big'3-46一一表的结构'ih_goods'9—10
1112CREATETABLEIFNOTEXISTS'ih_goods'('goods_id'int(10)unsignedNOTNULLAUTO」NCREMENT,14'cat_id'int(ll)NOTNULL,15'goods_name'varchar(255)NOTNULL,16PRIMARYKEY('goods_id')7)ENGINE=MyISAMDEFAULTCHARSET=utf8AUTO_INCREMENT=2;181920--21--转存表中的数据'ih_goods'22-2324INSERTINTO'ih_goods'('goods_id','cat_id','goods_name')VALUES26(1,0,'小米手机’);2728-- 2930--31--表的结构'ih_log'32-33CREATETABLEIFNOTEXISTS'ih_log'(35'id'int(ll)NOTNULLAUTO_INCREMENT,36'event'varchar(255)NOTNULL,'type'tinyint(4)NOTNULLDEFAULT'0','addtime'timestampNOTNULLDEFAULTCURRENT_TIMESTAMP,39PRIMARYKEY('id'))ENGINE=MyISAMDEFAULTCHARSET=utf8AUTO__INCREMENT=1;4142--43--转存表中的数据'ih__log'44--454647 4849----表的结构'ih_order'51-52CREATETABLEIFNOTEXISTS'ih_order'('id'int(ll)NOTNULLAUTOJNCREMENT,55'order_sn'char(32)NOTNULL,56'user_id'int(ll)NOTNULL,57'status'int(ll)NOTNULLDEFAULT'0:58goods_id'int(ll)NOTNULLDEFAULT'0:59'sku_id'int(ll)NOTNULLDEFAULT'0’,60'price'floatNOTNULL,61'addtime'timestampNOTNULLDEFAULTCURREN^TIMESTAMP,62PRIMARYKEY('id'))ENGINE=InnoDBDEFAULTCHARSET=utf8COMMENT='订单表'AUTO」NCREMENT=1;6465----转存表中的数据'ih_order'67-686970 7172--73--表的结构'ih_store'74-7576CREATETABLEIFNOTEXISTS'ih_store'(77'id'int(ll)NOTNULLAUTOJNCREMENT,78'goods_id'int(ll)NOTNULL,'sku_id'int(10)unsignedNOTNULLDEFAULT*0*,'number'int(10)NOTNULLDEFAULT'0’,81freez'int(ll)NOTNULLDEFAULT'0*COMMENT,虚拟库存82PRIMARYKEY('id'))ENGINE=InnoDBDEFAULTCHARSET=utf8COMMENT='库存'AUTO_INCREMENT=2;8485----转存表中的数据'ih_store'87-88B9INSE
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年环保型汽车运输汽油专项合同模板3篇
- 下年个人工作计划
- 2024年单位福利房产权转让及后续物业管理合同3篇
- 买卖合同范文集锦6篇
- 2022销售类工作计划
- 工程合同汇编七篇
- 主任工作计划模板
- 中国其他贵金属冶炼行业分析报告
- 年度商务工作计划
- 读三国演义有感600字寒假作文
- 市场营销试题(含参考答案)
- 九年级化学下册 第9单元 课题1《溶液的形成》教案 (新版)新人教版
- 景区旅游安全风险评估报告
- 电气工程及其自动化职业规划课件
- 2023年新高考(新课标)全国2卷数学试题真题(含答案解析)
- 2024年计算机二级WPS考试题库380题(含答案)
- 上海科学六年级上册知识点
- 2024年中煤平朔集团有限公司招聘笔试参考题库含答案解析
- 展厅展馆中控系统解决方案
- 儿童福利个人工作总结报告
- 《夜宿山寺》
评论
0/150
提交评论