啥都不说了,看代码
前台:
包括开始和结束的秒杀时间,倒计时插件,统一看一遍再去写代码,思路会更清晰。
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();
}
}
}
}