使用redis队列,因为pop操作是原子的,即使有很多用户同时到达,也是依次执行,推荐使用(mysql事务在高并发下性能下降很厉害,文件锁的方式也是)先将商品库存如队列<?php
$store=1000;
$redis=new Redis();
$result=$redis->connect('127.0.0.1',6379);
$res=$redis->llen('goods_store');
echo $res;
$count=$store-$res;
for($i=0;$i
$redis->lpush('goods_store',1);
}
echo $redis->llen('goods_store');
?>抢购、描述逻辑<?php
$conn=mysql_connect("localhost","big","123456");
if(!$conn){
echo "connect failed";
exit;
}
mysql_select_db("big",$conn);
mysql_query("set names utf8");
$price=10;
$user_id=1;
$goods_id=1;
$sku_id=11;
$number=1;
//生成唯一订单号
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){
global $conn;
$sql="insert into ih_log(event,type)
values('$event','$type')";
mysql_query($sql,$conn);
}
//模拟下单操作
//下单前判断redis队列库存量
$redis=new Redis();
$result=$redis->connect('127.0.0.1',6379);
$count=$redis->lpop('goods_store');
if(!$count){
insertLog('error:no store redis');
return;
}
//生成订单
$order_sn=build_order_no();
$sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price)
values('$order_sn','$user_id','$goods_id','$sku_id','$price')";
$order_rs=mysql_query($sql,$conn);
//库存减少
$sql="update ih_store set number=number-{$number} where sku_id='$sku_id'";
$store_rs=mysql_query($sql,$conn);
if(mysql_affected_rows()){
insertLog('库存减少成功');
}else{
insertLog('库存减少失败');
}
上述只是简单模拟高并发下的抢购,真实场景要比这复杂很多,很多注意的地方
如抢购页面做成静态的,通过ajax调用接口
再如上面的会导致一个用户抢多个,思路:排队队列
抢购结果队列
库存队列。
高并发情况,先将用户进入排队队列,从排队队列取出一个用户,判断用户是否已在抢购结果队列,如果在,则已抢购,否则未抢购,库存减1,写数据库,将用户入结果队列这里提供一个思路:
//排队队列
$strQueueName = 'paidui';
define('MAX_REQUEST',10);
if ( $strCount < MAX_REQUEST ) {
$redis->rpush($strQueueName, json_encode(['uid' => 1,'name' => 'Job']));
}else {
echo '已购完';
exit;
}
// 处理抢购 逻辑
// 对比 抢购结果队列, 该用户是否已经购买过商品
$userinfo = $redis->lpop('qiangou_list');
if ( is_result_qianggou($userinfo['id']) ) {
echo '已经购买过了';
exit;
}
// 1. 判断商品是否还有
$count=$redis->lpop('goods_store');
if ( !$count ) {
echo "没有了";
}
// 处理抢购逻辑
insert_mysql_goods();
$redis->rpush('qianggou_result', json_encode(['uid' => 1,'name' => 'Job'])); // 加入到抢购结果队列
// 抢购结束后,
// 异步存入 抢购结果 到mysql
$_qianggou = $redis->lpop('qianggou');
ps: 只是一个思路引子,具体线上服务,根据自己的场景. 异步, 静态化,cache. 订阅,发布.
本文由 舒舒 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: Mar 16, 2017 at 03:12 pm