php+redis秒杀

啥都不说了,看代码

前台:

包括开始和结束的秒杀时间,倒计时插件,统一看一遍再去写代码,思路会更清晰。

 js文件引入一个.min.js和一个插件js(在下面,自己复制吧)

// JavaScript Document
$(function(){
    
    //计算内容上下padding
    reContPadding({main:"#main",header:"#header",footer:"#footer"});
    function reContPadding(o){
        var main = o.main || "#main",
            header = o.header || null,
            footer = o.footer || null;
        var cont_pt = $(header).outerHeight(true),
            cont_pb = $(footer).outerHeight(true);
        $(main).css({paddingTop:cont_pt,paddingBottom:cont_pb});
    }
});

html代码:

<span id="t_d">00天</span>
<span id="t_h">00时</span>
<span id="t_m">00分</span>
<span id="t_s">00秒</span>

<input type="hidden" id="start" value="<?php date_default_timezone_set('PRC');echo  strtotime(date('Y-m-d H:i:s'))-strtotime($goods['start_time']);?>">
<input type="hidden" id="end" value="<?php date_default_timezone_set('PRC');echo strtotime(date('Y-m-d H:i:s'))-strtotime($goods['end_time'])?>" >


<script type="text/javascript">
   //判断时间
        var start = document.getElementById("start").value;
        var end = document.getElementById("end").value;
      if(start>=0 && end<0)
      {
         timer(end*-1);
      }

    function timer(intDiff) {
        window.setInterval(function () {
            var day = 0,
                hour = 0,
                minute = 0,
                second = 0; //时间默认值
            if (intDiff > 0) {
                day = Math.floor(intDiff / (60 * 60 * 24));
                hour = Math.floor(intDiff / (60 * 60)) - (day * 24);
                minute = Math.floor(intDiff / 60) - (day * 24 * 60) - (hour * 60);
                second = Math.floor(intDiff) - (day * 24 * 60 * 60) - (hour * 60 * 60) - (minute * 60);
            }
            if (minute <= 9) minute = '0' + minute;
            if (second <= 9) second = '0' + second;
            $('#t_d').html(day + "");
            $('#t_h').html('<s id="h"></s>' + hour + '');
            $('#t_m').html('<s></s>' + minute + '');
            $('#t_s').html('<s></s>' + second + '');
            intDiff--;
        }, 1000);
    }



    function GetRTime(end){

        var EndTime= new Date(end);
        var NowTime = new Date();
        var t =EndTime.getTime() - NowTime.getTime();
        var d=0;
        var h=0;
        var m=0;
        var s=0;
        if(t>=0){
            d=Math.floor(t/1000/60/60/24);
            h=Math.floor(t/1000/60/60%24);
            m=Math.floor(t/1000/60%60);
            s=Math.floor(t/1000%60);
        }


        document.getElementById("t_d").innerHTML = d + "";
        document.getElementById("t_h").innerHTML = h + "";
        document.getElementById("t_m").innerHTML = m + "";        document.getElementById("t_s").innerHTML = s + "";    }   $(function () {        $(".ms").click(function () {            var id = $(this).attr("ids");            $.ajax({                type: "get",                url: "?r=ms/buyms",                data: {id:id},            dataType:"json",                success: function(msg){                    alert(msg['message'])                }            });        })    })</script>

 

后台:

展示商品时,首先应该想到静态页面去优化服务器(我是根据详情页用id查询并赋值):

 /**
     * @param $gid
     * 生成静态页面
     *
     */
    public function actionOb($gid)
    {
        $goods_statis_file = "../views/pages/goods/ms_".md5($gid).".html";//对应静态页文件
        if(file_exists($goods_statis_file)){
            ob_start();
            flush();
            echo file_get_contents($goods_statis_file);//输出静态文件内容
            exit;
        }else{
            ob_start();

            //从数据库读取数据,并赋值给相关变量
            $goods = yii::$app->db->createCommand("select * from gobuy as go inner join goods as g on go.buy_goods_id=g.goods_id where g.goods_id='$gid'")->queryOne();
            include ("../views/goods/product_ms.html");//加载对应的商品详情页模板
            $content = ob_get_contents();//把详情页内容赋值给$content变量
            file_put_contents($goods_statis_file,$content);//写入内容到对应静态文件中
            ob_end_flush();//输出商品详情页信息
        }

    }

秒杀的方法:


<?php
namespace frontendcontrollers;

use Yii;
use yiiwebController;

/**
 * Site controller
 */
class MsController extends Controller
{
    public $layout = false;

    /**
     * 商品只能购买一件商品   商品ID、当前用户ID、商品数量,存入redis,
     * 通知当前用户,秒杀成功,或失败
     * 并将redis的商品库存队列 递减
     *
     */
    public function actionBuyms(){
//设置当前时间是中国时区
        date_default_timezone_set('PRC');
//      接受商品ID  ajax传来的id
//      $goods_id = yii::$app->request->get('goods_id');
        $goods_id=1;
//      当前登录用户ID
        $user_id = 1;
//      当前时间
        $date = date('Y-m-d H:i:s');
//      首先判断开始时间是否到
//      在队列查询开始时间
        $start_time = Yii::$app->redis->get('start_time'.$goods_id);
        if(empty($start_time)||$start_time>$date){
            echo json_encode(array('code'=>1002,'message'=>'秒杀时间还未开始'));exit;
        }
//      判断结束时间是否到
        $end_time  = Yii::$app->redis->get('end_time'.$goods_id);
        if(empty($end_time)||$date>=$end_time){
            echo json_encode(array('code'=>1002,'message'=>'秒杀已经结束了'));exit;
        }
        //取出储存在redis里的库存
       $num = Yii::$app->redis->get('num'.$goods_id);
        if($num<=0){
            echo json_encode(array('code'=>1001,'message'=>'已被抢空了...请等待下次抢购'));exit;
        }else{           
       $msg = json_encode(['user_id'=>1,'goods_id'=>1,'buy_num'=>$goods_id]);            
    //更新库存  decr递减            
    $u=Yii::$app->redis->decr('num'.$goods_id);            
    if($u) {               
     //储存用户信息到用户的队列   秒杀人员的总队列                
      Yii::$app->redis->lpush('yes_buy',$msg);               
        echo json_encode(array('code'=>1000,'message'=>'抢购成功,稍后为您出单,预计时间3分钟'));            
}       
}    
}    
/**     * @return string     *     * 生成订单为定时任务     在服务器每两分钟执行一次,等待1分钟     */    
/**     * 设置初始值,理论上,应为后台管理员手动设定秒杀商品     *     *     * 模拟给予   开始时间、结束时间、库存在redis储存的值     */    
public function actionSetbuyuser(){        
//默认开始时间为    2017-03-28 00:00:00        
$start_time = '2017-03-28 00:00:00';       
//默认结束时间为    2017-03-28 00:00:00       
$end_time = '2017-03-28 24:00:00';       
//默认库存为1        $num = 10;        
//商品id   为了区分商品信息、库存   不会打乱各个商品信息        
$goods_id = 1;        //设置库存        
Yii::$app->redis->set('num'.$goods_id,$num);        
//设置当前商品的开始时间        
Yii::$app->redis->set('start_time'.$goods_id,$start_time);       
//设置当前商品的结束时间        
Yii::$app->redis->set('end_time'.$goods_id,$end_time);    
}
}



yii2有个console定时任务:

Windows下命令行执行这个文件,linux用crontab定时任务执行也可以直接yii执行

下面代码意思是,将队列的信息一个个推出销毁,并入库生成订单返回给用户


<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

namespace consolecontrollers;
use yii;
use yiiconsoleController;

/**
 * This command echoes the first argument that you have entered.
 *
 * This command is provided as an example for you to learn how to create console commands.
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @since 2.0
 */
class TestController extends Controller
{
    /**
     * This command echoes what you have entered as the message.
     * @param string $message the message to be echoed.
     */

    public function actionIndex()
    {
        while (true){
         //获取队列最右用户信息
            $inf=yii::$app->redis->brpop('yes_buy',30);

            if(empty($inf))
            {
                break;
            }
            $info=json_decode($inf[1],true);
            //将商品信息查询出来
            $goods = yii::$app->db->createCommand("select * from goods where goods_id=1")->queryOne();
        //生成订单
            //获取唯一订单号
            $date = date('Y-m-d H:i:s');
            $sn=date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);


            $inser="insert into `order`(`order_sn`,`order_price`,`order_user`,`order_time`,`goods_num`,`goods_id`)values('".$sn."','".$goods['goods_price']*$info['buy_num']."','".$info['user_id']."','".$date."','".$info['buy_num']."','".$info['goods_id']."')";

            $or = yii::$app->db->createCommand($inser)->execute();           
       if($or)
        {
       //库存减少 订单生成一个,库存减少一个
        $sql="update gobuy set buy_num=buy_num-1 where buy_goods_id=".$info['goods_id'];
         $or = yii::$app->db->createCommand($sql)->execute();
          }
          }
        }
    }
原文地址:https://www.cnblogs.com/dwj97/p/6675530.html