php秒杀防重复中奖_php 用redis实现限时抢购,并且防止超卖和重复购买

  • Post author:
  • Post category:php


* 构造

*

* @return MyPDO*/

private function __construct($dbHost, $dbUser, $dbPasswd, $dbName, $dbCharset) {try{$this->dsn = ‘mysql:host=‘.$dbHost.‘;dbname=‘.$dbName;$this->dbh = new PDO($this->dsn, $dbUser, $dbPasswd);$this->dbh->exec(‘SET character_set_connection=‘.$dbCharset.‘, character_set_results=‘.$dbCharset.‘, character_set_client=binary‘);

}catch (PDOException $e) {exit($e->getMessage());

}

}/**

* 防止克隆

**/

private function__clone() {

}/**

* Singleton instance

*

* @return Object*/

public static function getInstance($dbHost, $dbUser, $dbPasswd, $dbName, $dbCharset) {if (self::$_instance === null) {

self::$_instance = new self($dbHost, $dbUser, $dbPasswd, $dbName, $dbCharset);

}return self::$_instance;

}/**

* Query 查询*/

public function query($strSql, $queryMode = ‘All‘, $debug = false) {if ($debug === true) $this->debug($strSql);$recordset = $this->dbh->query($strSql);if ($recordset) {$recordset->setFetchMode(PDO::FETCH_ASSOC);if ($queryMode == ‘All‘) {$result = $recordset->fetchAll();

}elseif ($queryMode == ‘Row‘) {$result = $recordset->fetch();

}

}else{$result = null;

}return $result;

}/**

* Insert 插入*/

public function insert($table, $arrayDataValue, $debug = false) {$strSql = “INSERT INTO `$table` (`”.implode(‘`,`‘, array_keys($arrayDataValue)).”`) VALUES (‘”.implode(“‘,‘”, $arrayDataValue).”‘)”;if ($debug === true) $this->debug($strSql);$result = $this->dbh->exec($strSql);return $result;

}/**

* 执行语句*/

public function execSql($strSql, $debug = false) {if ($debug === true) $this->debug($strSql);$result = $this->dbh->exec($strSql);return $result;

}/**

* debug

*

* @param mixed $debuginfo*/

private function debug($debuginfo) {var_dump($debuginfo);exit();

}

}classTest {private static $instance = null;//用单列模式 实例化Redis

public static functionRedis() {if (self::$instance == null) {$redis=newRedis();$redis->connect(‘127.0.0.1‘,6379);

self::$instance = $redis;

}return self::$instance;

}public function getOne($sql) {$db = MyPDO::getInstance(‘localhost‘, ‘root‘, ‘168168‘, ‘test‘, ‘utf8‘);$data = $db->query($sql)[0];return $data;

}public function exec($sql) {$db = MyPDO::getInstance(‘localhost‘, ‘root‘, ‘168168‘, ‘test‘, ‘utf8‘);return $db->execSql($sql);

}public function insert($table,$data) {$db = MyPDO::getInstance(‘localhost‘, ‘root‘, ‘168168‘, ‘test‘, ‘utf8‘);return $db->insert($table,$data);

}//将商品库存循环到lpush的num里

public functiondoPageSaveNum() {$redis=self::Redis();$goods_id=1;$sql=”select id, num,money from ims_hotmallstore_goods where id=”.$goods_id;$goods = $this->getOne($sql);//print_r($goods);die;

if(!empty($goods[‘num‘])) {for ($i=1; $i<=$goods[‘num‘]; $i++) {$redis->lpush(‘num‘,$i);

}die(‘成功!库存数:‘.$goods[‘num‘]);

}else{die(‘数据库已无库存‘);

}

}//抢购下单

public functiondoPageGoodsStore() {$redis=self::Redis();$goods_id=1;$user_id = mt_rand(1,100);if ($redis->sismember(‘user_list_‘.$goods_id,$user_id)) {echo ‘已下单‘;return false;

;

}$count=$redis->rpop(‘num‘);//每次从num取出1,防止超卖

if($count==0) {$this->echoMsg(0,‘已无库存‘);

}//加入已购买用户集合,防止重复购买

$redis->sAdd(‘user_list_‘.$goods_id,$user_id);$sql=”select id, num, money from ims_hotmallstore_goods where id=”.$goods_id;$goods = $this->getOne($sql);$this->doPageGoodsOrder($user_id,$goods,1);

}public functionorderNo() {return date(‘ymd‘).substr(implode(NULL, array_map(‘ord‘, str_split(substr(uniqid(), 7, 13), 1))), 0, 8);

}//下单更新库存

public function doPageGoodsOrder($user_id,$goods,$goods_number) {$orderNo=$this->orderNo();$number=$goods[‘num‘]-$goods_number;if($number<0) {$this->echoMsg(0,‘已没有库存‘);

}//mysql判断已购买用户 (自行处理)

//…

$order[‘user_id‘]=$user_id;$order[‘goods_id‘]=$goods[‘id‘];$order[‘number‘]=$goods_number;$order[‘price‘]=$goods[‘money‘];$order[‘status‘]=1;$order[‘sku_id‘]=2;$order[‘order_sn‘]=$orderNo;$order[‘create_time‘]=date(‘Y-m-d H:i:s‘);$this->insert(‘ims_order‘,$order);$sql=”update ims_hotmallstore_goods set num=num-“.$goods_number.” where num>0 and id=”.$goods[‘id‘];$res=$this->exec($sql);//echo $sql;die;

if(!empty($res)) {echo “库存扣减成功,库存剩下:$number”.PHP_EOL;return false;

}else{$redis=self::Redis();$redis->lpush(‘num‘,$goods_number);//扣库存失败,把库存加回

$redis->SREM(‘user_list_‘.$goods_id,$user_id);//已购买用户集合移除

$this->echoMsg(0,‘库存扣减失败‘);

}

}//保存日志

public function echoMsg($status,$msg,$exit = true) {if($exit == true) {die($msg);

}else{echo $msg;

}

}

}if(!isset($_GET[‘i‘])) {exit(‘缺失参数i‘);

}//调用–将商品库存循环到lpush的num里

if($_GET[‘i‘]==1) {$model = newTest;$model->doPageSaveNum();

}//调用–高并发抢购下单

if($_GET[‘i‘]==2) {$model = newTest;$model->doPageGoodsStore();

}if($_GET[‘i‘]==3) {$model = newTest;for ($i=1; $i<=100; $i++) {$model->doPageGoodsStore();

}

}//http://127.0.0.1/qianggou/test.php?i=1

// ab -n 2000 -c 500 http://127.0.0.1/qianggou/test.php?i=2

// (-n发出2000个请求,-c模拟500并发,请求数要大于或等于并发数。相当2000人同时访问,后面是测试url )



版权声明:本文为weixin_35513425原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。