使用redis實現簡單的秒殺
阿新 • • 發佈:2017-05-18
lec connect use decode else 隊列 def 固定 urn
自己做的簡單秒殺 感覺思路是沒太大問題的 但是代碼寫的不是很好 做個記錄方便以後回來嘲諷下自己
<?php
namespace frontend\controllers;
use Yii;
use frontend\models\Goods;
use frontend\models\Order;
use yii\web\Controller;
define(‘chenggong‘,1);
define(‘yishouwan‘,4);
define(‘weidenglu‘,5);
class SeckillController extends Controller
{
public function actionIndex()
{
return $this->render(‘index‘);
}
/**
* @return string
*/
public function actionSeckill()
{
//獲取到前臺傳來的商品ID及其他信息
$goods_id = yii::$app->request->post(‘gid‘);
//獲取當前登錄用戶ID 如未提示先登錄 此處為模擬實現
$user_id = mt_rand(1,100);
if (!$user_id){
return json_encode(weidenglu);
}
//連接redis
$redis = new \Redis();
$redis->connect(‘127.0.0.1‘,6379);
//從redis取出對應商品庫存 如不存在 先存
$goods_num = $redis->get(‘goodsNum_‘.$goods_id);
if (!$goods_num){
//在商品被搶完的情況下 也會執行 !$goods_num 即 $goods_num == 0 時 執行 !$goods_num
if ($goods_num === ‘0‘){
return json_encode(yishouwan);
}else{
//去商品庫查詢庫存存入redis鏈表
$goodsModel = new Goods();
$goods_num = $goodsModel->find()->select(‘num‘)->where("id = $goods_id")->asArray(true)->one();
$goods_num = $goods_num[‘num‘] - 1;
//庫存減一 執行秒殺
$redis->set(‘goodsNum_‘.$goods_id,$goods_num);
//秒殺成功 訂單數據存入redis 後臺自動執行添加訂單
$info = json_encode([‘user_id‘=>$user_id,‘goods_id‘=>$goods_id]);
$redis->lPush(‘buy_‘.$goods_id,$info);
return json_encode(chenggong);
}
}else{
$goods_num = $redis->decr(‘goodsNum_‘.$goods_id);
if ($goods_num<0){
return json_encode(yishouwan);
}else{
//秒殺成功 訂單數據存入redis 後臺自動執行添加訂單
$info = json_encode([‘user_id‘=>$user_id,‘goods_id‘=>$goods_id]);
$redis->lPush(‘buy_‘.$goods_id,$info);
return json_encode(chenggong);
}
}
}
/*
* 感覺自己這個腳本寫的有問題,現在知識有限 ,待以後在升級吧
*
* 此段代碼應轉入腳本自動後臺執行
* 取出隊列中的訂單信息,並存入數據庫
*/
public function actionKill()
{
//設置程序開始結束時間 建議以shell腳本開始 程序自動結束
$time1 = ‘2017-05-12 09:18:45‘;
$time2 = ‘2017-05-13 09:18:45‘;
if (time() < strtotime($time1) || time() > strtotime($time2)){
return false;
}
//設置程序最大執行時間 0 為一直執行下去 單位為秒
set_time_limit(0);
$goods_id = 2;
$redis = new \Redis();
$redis->connect(‘127.0.0.1‘,6379);
$goodsModle = new Order();
//從redis中取出相關訂單信息
$order = $redis->rPop(‘buy_‘.$goods_id);
if (!$order){
/*
* 如果沒有相關信息,等待固定時間後重新執行,
* 或者不等待直接重新執行,一定要有程序結束時間
* 否則程序會一直執行下去,消耗大量資源
*
* 程序最大執行時間為30s ,註意要設置執行時間
*
* 程序調用自己效率會非常慢 , 不推薦 ,待以後改進
*/
$this->actionkill();
return false;
}
//生成唯一訂單號
$order = $this->object_to_array(json_decode($order));
$order[‘order_no‘] = date(‘YmdHis‘).substr(implode(NULL, array_map(‘ord‘, str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
$order[‘price‘] = 1000;
//訂單入庫
$goodsModle->add($order);
//此處同上 程序執行結束後繼續執行
$this->actionkill();
return true;
}
/**
* 數組 轉 對象
*
* @param array $arr 數組
* @return object
*/
public function array_to_object($arr)
{
if (gettype($arr) != ‘array‘) {
return;
}
foreach ($arr as $k => $v) {
if (gettype($v) == ‘array‘ || getType($v) == ‘object‘) {
$arr[$k] = (object)array_to_object($v);
}
}
return (object)$arr;
}
/**
* 對象 轉 數組
*
* @param object $obj 對象
* @return array
*/
public function object_to_array($obj)
{
$obj = (array)$obj;
foreach ($obj as $k => $v) {
if (gettype($v) == ‘resource‘) {
return;
}
if (gettype($v) == ‘object‘ || gettype($v) == ‘array‘) {
$obj[$k] = (array)object_to_array($v);
}
}
return $obj;
}
}
使用redis實現簡單的秒殺