php+redis實現(xiàn)商城秒殺功能
好久沒來整理文章了,閑了沒事寫篇文章記錄下php+redis實現(xiàn)商城秒殺功能。
1、安裝redis,根據(jù)自己的php版本安裝對應(yīng)的redis擴(kuò)展(此步驟簡單的描述一下)
1.1.安裝php_igbinary.dll,php_redis.dll擴(kuò)展此處需要注意你的php版本如圖:
1.2.php.ini文件新增extension=php_igbinary.dll;extension=php_redis.dll兩處擴(kuò)展
ok此處已經(jīng)完成第一步redis環(huán)境搭建完成看看phpinfo
2、項目中實際使用redis
2.1.第一步配置redis參數(shù)如下,redis安裝的默認(rèn)端口為6379:
<?php /* 數(shù)據(jù)庫配置 */ return array( 'DATA_CACHE_PREFIX' => 'Redis_',//緩存前綴 'DATA_CACHE_TYPE'=>'Redis',//默認(rèn)動態(tài)緩存為Redis 'DATA_CACHE_TIMEOUT' => false, 'REDIS_RW_SEPARATE' => true, //Redis讀寫分離 true 開啟 'REDIS_HOST'=>'127.0.0.1', //redis服務(wù)器ip,多臺用逗號隔開;讀寫分離開啟時,第一臺負(fù)責(zé)寫,其它[隨機(jī)]負(fù)責(zé)讀; 'REDIS_PORT'=>'6379',//端口號 'REDIS_TIMEOUT'=>'300',//超時時間 'REDIS_PERSISTENT'=>false,//是否長連接 false=短連接 'REDIS_AUTH'=>'',//AUTH認(rèn)證密碼 ); ?>
2.2.實際函數(shù)中使用redis:
/** * redis連接 * @access private * @return resource * @author bieanju */ private function connectRedis(){ $redis=new \Redis(); $redis->connect(C("REDIS_HOST"),C("REDIS_PORT")); return $redis; }
2.3. 秒殺的核心問題是在大并發(fā)的情況下不會超出庫存的購買,這個就是處理的關(guān)鍵所以思路是第一步在秒殺類的先做一些基礎(chǔ)的數(shù)據(jù)生成:
//現(xiàn)在初始化里面定義后邊要使用的redis參數(shù) public function _initialize(){ parent::_initialize(); $goods_id = I("goods_id",'0','intval'); if($goods_id){ $this->goods_id = $goods_id; $this->user_queue_key = "goods_".$goods_id."_user";//當(dāng)前商品隊列的用戶情況 $this->goods_number_key = "goods".$goods_id;//當(dāng)前商品的庫存隊列 } $this->user_id = $this->user_id ? $this->user_id : $_SESSION['uid']; }
2.4. 第二步就是關(guān)鍵所在,用戶在進(jìn)入商品詳情頁前先將當(dāng)前商品的庫存進(jìn)行隊列存入redis如下:
/** * 訪問產(chǎn)品前先將當(dāng)前產(chǎn)品庫存隊列 * @access public * @author bieanju */ public function _before_detail(){ $where['goods_id'] = $this->goods_id; $where['start_time'] = array("lt",time()); $where['end_time'] = array("gt",time()); $goods = M("goods")->where($where)->field('goods_num,start_time,end_time')->find(); !$goods && $this->error("當(dāng)前秒殺已結(jié)束!"); if($goods['goods_num'] > $goods['order_num']){ $redis = $this->connectRedis(); $getUserRedis = $redis->hGetAll("{$this->user_queue_key}"); $gnRedis = $redis->llen("{$this->goods_number_key}"); /* 如果沒有會員進(jìn)來隊列庫存 */ if(!count($getUserRedis) && !$gnRedis){ for ($i = 0; $i < $goods['goods_num']; $i ++) { $redis->lpush("{$this->goods_number_key}", 1); } } $resetRedis = $redis->llen("{$this->goods_number_key}"); if(!$resetRedis){ $this->error("系統(tǒng)繁忙,請稍后搶購!"); } }else{ $this->error("當(dāng)前產(chǎn)品已經(jīng)秒殺完!"); } }
接下來要做的就是用ajax來異步的處理用戶點(diǎn)擊購買按鈕進(jìn)行符合條件的數(shù)據(jù)進(jìn)入購買的排隊隊列(如果當(dāng)前用戶沒在當(dāng)前產(chǎn)品用戶的隊列就進(jìn)入排隊并且pop一個庫存隊列,如果在就拋出,):
/** * 搶購商品前處理當(dāng)前會員是否進(jìn)入隊列 * @access public * @author bieanju */ public function goods_number_queue(){ !$this->user_id && $this->ajaxReturn(array("status" => "-1","msg" => "請先登錄")); $model = M("flash_sale"); $where['goods_id'] = $this->goods_id; $goods_info = $model->where($where)->find(); !$goods_info && $this->error("對不起當(dāng)前商品不存在或已下架!"); /* redis 隊列 */ $redis = $this->connectRedis(); /* 進(jìn)入隊列 */ $goods_number_key = $redis->llen("{$this->goods_number_key}"); if (!$redis->hGet("{$this->user_queue_key}", $this->user_id)) { $goods_number_key = $redis->lpop("{$this->goods_number_key}"); } if($goods_number_key){ // 判斷用戶是否已在隊列 if (!$redis->hGet("{$this->user_queue_key}", $this->user_id)) { // 插入搶購用戶信息 $userinfo = array( "user_id" => $this->user_id, "create_time" => time() ); $redis->hSet("{$this->user_queue_key}", $this->user_id, serialize($userinfo)); $this->ajaxReturn(array("status" => "1")); }else{ $modelCart = M("cart"); $condition['user_id'] = $this->user_id; $condition['goods_id'] = $this->goods_id; $condition['prom_type'] = 1; $cartlist = $modelCart->where($condition)->count(); if($cartlist > 0){ $this->ajaxReturn(array("status" => "2")); }else{ $this->ajaxReturn(array("status" => "1")); } } }else{ $this->ajaxReturn(array("status" => "-1","msg" => "系統(tǒng)繁忙,請重試!")); } }
附加一個調(diào)試的函數(shù),刪除指定隊列值:
public function clearRedis(){ set_time_limit(0); $redis = $this->connectRedis(); //$Rd = $redis->del("{$this->user_queue_key}"); $Rd = $redis->hDel("goods49",'用戶id''); $a = $redis->hGet("goods_49_user", '用戶id'); if(!$a){ dump($a); } if($Rd == 0){ exit("Redis隊列已釋放!"); } }
走到此處的時候秒殺的核心基本就完了,細(xì)節(jié)還需要自己在去完善,像購物車這邊的處理還有訂單的處理,好吧開始跑程序利用apache自身的ab可以進(jìn)行簡單的模擬并發(fā)測試如下:
跑起來,我擦跑步起來redis沒有任何反應(yīng),此時還少一步重要的步驟就是開啟redis服務(wù),請根據(jù)自己的系統(tǒng)下一個redisbin_x32或者redisbin_x64的redis服務(wù)管理工具,點(diǎn)擊redis-server.exe,ok至此全部完成如下圖:
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- php操作redis數(shù)據(jù)庫常見方法實例總結(jié)
- PHP操作Redis數(shù)據(jù)庫常用方法示例
- PHP數(shù)據(jù)庫操作三:redis用法分析
- PHP實現(xiàn)的redis主從數(shù)據(jù)庫狀態(tài)檢測功能示例
- PHP的Laravel框架結(jié)合MySQL與Redis數(shù)據(jù)庫的使用部署
- php實現(xiàn)redis數(shù)據(jù)庫指定庫號遷移的方法
- 30個php操作redis常用方法代碼例子
- redis 隊列操作的例子(php)
- php結(jié)合redis實現(xiàn)高并發(fā)下的搶購、秒殺功能的實例
- php Session存儲到Redis的方法
- PHP操作Redis常用技巧總結(jié)
- php操作redis緩存方法分享
- php操作Redis數(shù)據(jù)庫基本示例【安裝、連接、設(shè)置、查詢、斷開】
相關(guān)文章
vscode運(yùn)行php報錯php?not?found解決辦法
這篇文章主要給大家介紹了關(guān)于vscode運(yùn)行php報錯php?not?found的解決辦法,這個問題可能是由于您的計算機(jī)上沒有安裝PHP或者VS?Code沒有正確配置PHP的路徑所導(dǎo)致的,文中將解決的辦法介紹的很詳細(xì),需要的朋友可以參考下2023-07-07Yii2針對游客、用戶防范規(guī)則和限制的解決方法分析
這篇文章主要介紹了Yii2針對游客、用戶防范規(guī)則和限制的解決方法,簡單分析了Yii2對于游客、用戶防范規(guī)則和限制的原理與相應(yīng)的設(shè)置方法,需要的朋友可以參考下2016-10-10py文件轉(zhuǎn)exe時包含paramiko模塊出錯解決方法
這篇文章主要介紹了py文件轉(zhuǎn)exe時包含paramiko模塊出錯解決方法的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-08-08PHP讀取mssql json數(shù)據(jù)中文亂碼的解決辦法
PHP及網(wǎng)頁使用UTF-8編碼,數(shù)據(jù)庫是sql server2008,使用默認(rèn)編碼,當(dāng)讀取數(shù)據(jù)庫數(shù)據(jù)時,使用php自帶的json_encode()返回到前端,結(jié)果中文不顯示。下面腳本之家小編給大家介紹PHP讀取mssql json數(shù)據(jù)中文亂碼的解決辦法,需要的朋友一起學(xué)習(xí)2016-04-04CodeIgniter框架數(shù)據(jù)庫基本操作示例
這篇文章主要介紹了CodeIgniter框架數(shù)據(jù)庫基本操作,結(jié)合實例形式分析了CodeIgniter框架針對mysql數(shù)據(jù)庫的配置、用戶注冊、信息查詢、修改及刪除等基本操作技巧,需要的朋友可以參考下2018-05-05Laravel 微信小程序后端實現(xiàn)用戶登錄的示例代碼
這篇文章主要介紹了Laravel 微信小程序后端實現(xiàn)用戶登錄的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11php 與 nginx 的處理方式及nginx與php-fpm通信的兩種方式
這篇文章主要介紹了php 與 nginx 的兩種處理方式及nginx與php-fpm通信的兩種方式,需要的朋友可以參考下2018-09-09