php商城下单,可以购买多件商品,redis防高并发
<?php
header('content-type:text/html;charset=utf-8');
echo time();
class SeckillRedis {
echo time();
class SeckillRedis {
static protected $validity_time = 300; // 有效期 5分钟
protected $goods_id;
protected $user_queue_key;
protected $goods_number_key;
protected $user_id;
protected $goods_id;
protected $user_queue_key;
protected $goods_number_key;
protected $user_id;
public function __construct($goods_id,$area_id,$uid){
if($goods_id){
$this->goods_id=$goods_id;
//当前商品队列的用户情况
$this->user_queue_key="goods_".$goods_id."_user";
//当前商品的库存队列
$this->goods_number_key="goods_".$goods_id;
}
$this->user_id=$uid ? $uid : 2;
}
/* redis链接 */
static public function getRedis(){
$redis=new Redis();
$redis->connect('127.0.0.1','6379') or die('Can not Content Redis');
if($redis){
return $redis;
}else{
die('Can not Content Redis!');
}
}
$redis=new Redis();
$redis->connect('127.0.0.1','6379') or die('Can not Content Redis');
if($redis){
return $redis;
}else{
die('Can not Content Redis!');
}
}
// 添加或改变库存时初始化队列
public function kuCun($num){
$redis=$this->getRedis();
$redis->delete($this->goods_number_key);
$redis->delete($this->user_queue_key);
for ($i=0; $i < $num; $i++) {
public function kuCun($num){
$redis=$this->getRedis();
$redis->delete($this->goods_number_key);
$redis->delete($this->user_queue_key);
for ($i=0; $i < $num; $i++) {
$redis->rPush($this->goods_number_key, 1);
}
}
}
// 判断未支付订单是否过期 ,定时更新秒杀商品入口人数
public function poling_set_seckill_redis(){
$redis=$this->getRedis();
//exists检查key是否存在是否有值,存在返回1,不存在返回0,0也属于不存在的
if($redis->exists($this->user_queue_key) == true){
$redis=$this->getRedis();
//exists检查key是否存在是否有值,存在返回1,不存在返回0,0也属于不存在的
if($redis->exists($this->user_queue_key) == true){
// 清除过期的使用数量
$use_list = $redis->lRange($this->user_queue_key, 0, -1);
foreach ($use_list as $k => $v) {
foreach ($use_list as $k => $v) {
$data = json_decode($v, true);
if(time() - $data['time'] > self::$validity_time){
var_dump($v.'ww');
// 超过有效期 删除
var_dump($v.'ww');
// 超过有效期 删除
// $this->returnFree($k,$data['uid'],$data['num']);
$value = $redis->lGet($this->user_queue_key,$k);
if(!empty($value)){
// var_dump($value.'hh');
$value = $redis->lGet($this->user_queue_key,$k);
if(!empty($value)){
// var_dump($value.'hh');
//这里体现出来lrem的延迟性了,所以不用lrem
//$del=$redis->lrem($this->goods_number_key,$value,1);
$del=$redis->lpop($this->user_queue_key);
if($del!=''){
// 添加空闲数量
for ($i=0; $i < $data['num']; $i++) {
$redis->rPush($this->goods_number_key, 1);
}
}
// 添加空闲数量
for ($i=0; $i < $data['num']; $i++) {
$redis->rPush($this->goods_number_key, 1);
}
}
// $sql语句,库存加1
// return array('result' => true);
}else{
return array('result' => false, 'message' => '抢购信息:不存在索引');
}
}
}
}
}
/* 获取空闲抢购--num:购买件数 */
/* 获取空闲抢购--num:购买件数 */
public function getFree($num){
if(empty($this->user_id)){
return array('result' => false, 'message' => '抢购信息:用户ID不能为空');
}
$redis = self::getRedis();
if($redis->llen($this->goods_number_key)=='0'){
return array('result' => false, 'message' => '抢购信息:被抢光啦');
}
//可能并发大的有漏掉进去的
if($redis->llen($this->goods_number_key) >= $num){
file_put_contents('bb.log',var_export('123',true),FILE_APPEND);
return array('result' => false, 'message' => '抢购信息:被抢光啦');
}
//可能并发大的有漏掉进去的
if($redis->llen($this->goods_number_key) >= $num){
file_put_contents('bb.log',var_export('123',true),FILE_APPEND);
//用下面的循环,漏掉的订单过来,会减少库存量
// for ($i=0; $i < $num; $i++) {
// $result = $redis->lPop($this->goods_number_key);
// }
// for ($i=0; $i < $num; $i++) {
// $result = $redis->lPop($this->goods_number_key);
// }
//不得已用lrem
$result = $redis->lrem($this->goods_number_key,'1',$num);
// var_dump($redis->lrange($seckill_array[$type]['free_key'],0,-1));
if($result == true){
$result = $redis->lrem($this->goods_number_key,'1',$num);
// var_dump($redis->lrange($seckill_array[$type]['free_key'],0,-1));
if($result == true){
// 添加使用数量
$index = $redis->rPush($this->user_queue_key, json_encode(array('uid' => $this->user_id, 'time' => time(),'num' => $num))) - 1;
return array('result' => true, 'index' => $index);
}else{
return array('result' => false, 'message' => '抢购信息:被抢光啦');
}
}else{
return array('result' => false, 'message' => '抢购信息:库存不够');
}
}else{
return array('result' => false, 'message' => '抢购信息:库存不够');
}
}
/* 返回空闲抢购--$index为键值 */
public function returnFree($index,$uid,$num){
$redis = self::getRedis();
$value = $redis->lGet($this->user_queue_key,$index);
var_dump($value.'hh');
if(!empty($value)){
var_dump($value.'hh');
if(!empty($value)){
$redis->lRem($this->user_queue_key, $value, 1);
// 添加空闲数量
for ($i=0; $i < $num; $i++) {
$redis->rPush($this->goods_number_key, 1);
}
for ($i=0; $i < $num; $i++) {
$redis->rPush($this->goods_number_key, 1);
}
// $sql语句,库存加1
// return array('result' => true);
}else{
return array('result' => false, 'message' => '抢购信息:不存在索引');
}
}
}
class Index{
/* 某个需要控制并发的控制器方法 */
public function getOrderInfo(){
$uid=mt_rand(1,100);
$num=mt_rand(1,5);
$miaosha=new SeckillRedis('3','123',$uid);
// $miaosha->kuCun('20');
$miaosha->poling_set_seckill_redis();
$result = $miaosha->getFree('3');
return $result;
if($result['result'] == false){
$uid=mt_rand(1,100);
$num=mt_rand(1,5);
$miaosha=new SeckillRedis('3','123',$uid);
// $miaosha->kuCun('20');
$miaosha->poling_set_seckill_redis();
$result = $miaosha->getFree('3');
return $result;
if($result['result'] == false){
// 没有机会 返回错误信息
return '网络繁忙,请重试';
}
// 处理数据库代码
}
}
$hua = new Index;
var_dump($hua->getOrderInfo()).'<br>';
var_dump($hua->getOrderInfo()).'<br>';
尽量不要用lrem命令,因为这个命令有延迟,影响高并发过程,尽量用rpush、lpop等命令