秒殺是商城常見功能 php+redis是最常見的秒殺功能
1,安裝redis,根據自己的php版本安裝對應的redis擴展
首先查看phpinfo();php環境信息
2,下載redis
https://windows.php.net/downloads/pecl/snaps/redis/
https://windows.php.net/downloads/pecl/releases/igbinary/
一定要確認下載版本是否和php對應
3.解壓縮后,將php_redis.dll和php_redis.pdb拷貝至php的ext目錄下
4.修改php.ini,(PS:此php.ini文件是在Apache目錄)在該文件中加入:
; php_redis
extension=php_igbinary.dll
extension=php_redis.dll
注意:extension=php_igbinary.dll一定要放在extension=php_redis.dll的前面,否則此擴展不會生效
5.重啟Apache后,使用phpinfo查看擴展是否成功安裝
在config配置redis 我示例用的是thinkphp5.0
然后在extend下新建module文件夾 創建Redis.php文件
<?php
/**
* Created by PhpStorm.
* User: lhl
* Date: 2018/8/20
* Time: 下午1:52
*/
namespace module;
class Redis extends \Redis
{
public static function redis() {
$con = new \Redis();
$con->connect(config('redis.host'), config('redis.port'), 5);
return $con;
}
}
在thinkphp文件下的helper.php加入
if (!function_exists('redis')) {
/**
* 獲取容器對象實例
* @return Container
*/
function redis()
{
return \module\Redis::redis();
}
}
然后就可以在控制器寫redis緩存方法了
//創建redis緩存
\Cache::store('redis')->set(key, value);
//讀取緩存
\Cache::store('redis')->get(key);
秒殺的核心問題是在大並發的情況下不會超出庫存的購買,這個就是處理的關鍵所以思路是第一步在秒殺類的先做一些基礎的數據生成:
三張表做測試,分別是:商品表,日志表,訂單表,
///秒殺入口
public function insva(){
$id = input('id');//獲取商品id
if(!$id){
return $this->insertlog(0);//記錄失敗日志
}
$redis = $this->redis();//接入redis
$count = $redis->reduceStock('goods_stock');//減少庫存,返回剩余庫存
if($count ==0){
$this->insertlog(0);//記錄秒殺失敗日志
return false;
}else{
$order = $this->build_order_no();//隨機生成訂單號
$status = 1;
$data = db('goods')->where('id',$id)->find();
if (!$data){
return $this->insertlog(0);//商品不存在
}
$res = db('order')->insert(['order_sn'=>$order,'uid'=>$this->user_id,'goods_id'=>$id]);//插入訂單
$stock = db('goods')->where('id',$id)->setDec('count');//減少庫存
if($stock){
$this->insertlog();//記錄成功日志
}else{
$this->insertlog(0);//記錄秒殺失敗日志
}
}
}
// 將商品庫存存入隊列
public function redisinit(){
$store=50; // 庫存50
$redis=$this->redis(); //接入redis
$redis->del('goods_store'); // 刪除庫存列表
$res=$redis->llen('goods_store'); //返回庫存長度,這里已經是0
$count=$store-$res;
for($i=0;$i<$count;$i++){
$redis->lpush('goods_store',1); //列表推進50個,模擬50個商品庫存
}
}
//生成唯一訂單
function build_order_no(){
return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
}
// 記錄日志 狀態1成功 0失敗
function insertlog($status=1){
return Db::name("ab_log")->insertGetId(["count"=>1,"status"=>$status,"addtime"=>date('Y-m-d H:i:s')]);
}