#事先说明,本次的文章所贴的事例代码并非本人,具体出自什么地方?我也无从考究。不过今天要为大家讲的就是基于这些事例代码结合对应的个人理解进行分析。如果有什么觉得说得不正确的请各位看官拍砖。也让我学而知不足。
#关于秒杀抢购的思路一般都基于三个部分进行设计
1.用户页面层,这个部分可以设置页面缓存,cdn加速,适当的请求拦截。当然前两者相信各位很容易理解,那什么是请求拦截了?其实说白了就是当用户点击了提交按钮后,记得通过ajax把按钮设置为禁用状态。须知道用户在烦躁的时候可是会疯狂地点击提交按钮,这部分的请求如果你不过滤到那岂不是在白白浪费服务器的资源?
2.数据接入层,在数据接入层的这个层面来说我们一般我们就要对用户的请求进行判断,尽量把恶意的请求都拒绝在外,常见的做法就是同一个IP在限定的时间段内限制访问次数,或者通过记录用户的UID来限制用一个用户的UID在每分钟的请求次数,用来过滤一些高端用户通过脚本来参与请求的。
3.数据处理层,最后我们本次文章就是要基于数据处理层的代码展示来为大家说一下关于抢购的处理思路。其实对于抢购和秒杀的核心处理思路就是防止超卖,还有防止服务器迅时流量的爆增导致服务的崩溃。
那么我们先看一个传统的抢购流程
上面这个例子,假设某个抢购场景中,我们一共只有100个商品,在最后一刻,我们已经消耗了99个商品,仅剩最后一个。这个时候,系统发来多个并发请求,这批请求读取到的商品余量都是99个,然后都通过了这一个余量判断,最终导致超发。在上面的这个图中,就导致了并发用户B也“抢购成功”,多让一个人获得了商品。这种场景,在高并发的情况下非常容易出现。
优化方案1:将库存字段number字段设为unsigned,当库存为0时,因为字段不能为负数,将会返回false
<?php
//优化方案1:将库存字段number字段设为unsigned,当库存为0时,因为字段不能为负数,将会返回false
include('./mysql.php');
$username = 'wang'.rand(0,1000);
//生成唯一订单
function build_order_no(){
return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
}
//记录日志
function insertLog($event,$type=0,$username){
global $conn;
$sql="insert into ih_log(event,type,usernma)
values('$event','$type','$username')";
return mysqli_query($conn,$sql);
}
function insertOrder($order_sn,$user_id,$goods_id,$sku_id,$price,$username,$number)
{
global $conn;
$sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price,username,number)
values('$order_sn','$user_id','$goods_id','$sku_id','$price','$username','$number')";
return mysqli_query($conn,$sql);
}
//模拟下单操作
//库存是否大于0
$sql="select number from ih_store where goods_id='$goods_id' and sku_id='$sku_id' ";
$rs=mysqli_query($conn,$sql);
$row = $rs->fetch_assoc();
if($row['number']>0){//高并发下会导致超卖
if($row['number']<$number){
return insertLog('库存不够',3,$username);
}
$order_sn=build_order_no();
//库存减少
$sql