商品秒杀倒计时的实现
前台页面
商品秒杀页面
//查询今日所有的秒杀信息
$mysqli = new MYSQLi("127.0.0.1","root","root");
if($mysqli->connect_error){
die("连接错误".$mysqli->connect_error);
}
//设置字符集
$mysqli->set_charset('utf8');
$mysqli->select_db("miaosha");
//php的时间是以秒算。js的时间以毫秒算
date_default_timezone_set('PRC');
$sql = "select * from ih_store where to_days(start_time) = to_days(now());";
//执行sql语句
$result = $mysqli->query($sql);
// var_dump($result);die;
//把资源转化为数组
$data = [];
while($arr = $result->fetch_assoc())
{
$data[] = $arr;
}
//获取当前
$time = date("Y-m-d H:i:s",time());
//处理date数据
foreach($data as $k=>$v)
{
//0 表示还没有开始秒杀
//1 表示正在秒杀
//2 表示秒杀已经结束
//判断当前秒杀没有开始
if($v['start_time'] > $time)
{
//往数组中自定义一个字段,用于存放秒杀状态
//也可以传引用的方式(在foreach循环里在$v前加上&,即$&v),这样就可以将$data[$k]替换为$v
$data[$k]['content'] = '0';
}
else if($v['start_time'] <= $time && $v['end_time'] >= $time)
{
$data[$k]['content'] = '1';
}
else
{
$data[$k]['content'] = '2';
}
}
// echo "
";
// print_r($data);exit;
?>
秒杀商品 |
秒杀开始时间 |
秒杀结束时间 |
点击秒杀 |
foreach($data as $k=>$v){
?>
miaosha |
=$v['start_time']?> |
=$v['end_time']?> |
if($v['content'] == '0')
{
//调用函数
//date_default_timezone_set("Asia/Hong_Kong");//地区
//配置每天的活动时间段
$starttimestr = $v['start_time'];
$endtimestr = $v['end_time'];
$starttime = strtotime($starttimestr); //开始时间
$endtime = strtotime($endtimestr); //结束时间
$nowtime = time(); //当前时间
if ($nowtime<$starttime){
// die("活动还没开始,活动时间是:{$starttimestr}至{$endtimestr}");
}
if ($endtime>=$nowtime){
$lefttime = $starttime-$nowtime; //实际剩下的时间(秒)
}else{
$lefttime=0;
die("活动已经结束!");
}
echo "";
echo "";
}
else if($v['content'] == '1')
{
echo "点我秒杀";
}
else
{
echo '秒杀结束';
}
?>
|
}
?>
采用消息队列的方式
//现将商品库存入队列
- $store=1000;
- $redis=new Redis();
- $result=$redis->connect('127.0.0.1',6379);
- $res=$redis->llen('goods_store');
- //echo $res;
- $count=$store-$res;
- for($i=0;$i<$count;$i++){
- $redis->lpush('goods_store',1);
- }
- echo $redis->llen('goods_store');
- ?>
//抢购、秒杀描述
$mysqli = new MYSQLi("127.0.0.1","root","root");
if($mysqli->connect_error){
die("连接失败".$mysqli->connect_error);
}
$mysqli->set_charset('utf8');
$mysqli->select_db("miaosha");
$price=10;
$user_id=1;
$goods_id=1;
$sku_id=11;
$number=1;
//生成唯一订单
function build_order_no(){
return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
}
//记录日志
function insertLog($event,$type=0){
global $mysqli;
$sql="insert into ih_log(event,type)
values('$event','$type')";
$mysqli->query($sql);
}
//模拟下单操作
//库存是否大于0
$sql="select number from ih_store where goods_id='$goods_id' and sku_id='$sku_id'";//解锁 此时ih_store数据中goods_id='$goods_id' and sku_id='$sku_id' 的数据被锁住(注3),其它事务必须等待此次事务 提交后才能执行
$rs=$mysqli->query($sql);
// var_dump($rs);exit;
$row=$rs->fetch_assoc();
if($row['number']>0){//高并发下会导致超卖
$order_sn=build_order_no();
//生成订单
$sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price)
values('$order_sn','$user_id','$goods_id','$sku_id','$price')";
$order_rs=$mysqli->query($sql);
//库存减少
$sql="update ih_store set number=number-{$number} where sku_id='$sku_id'";
$store_rs=$mysqli->query($sql);
if($store_rs->affect_rows){
insertLog('库存减少成功');
}else{
insertLog('库存减少失败');
}
}else{
insertLog('库存不够');
}
/*
优化方案一:
将库存字段设置为unsigned(无符号,即不能有负数);
当库存为0时,因为字段不能为负数,将会返回false
**/
//去库存
// $sql = "update ih_store set number=number-{$number} where sku_id = '$sku_id' and number>0";
// $store_rs = $mysqli->query($sql);
// if($mysqli->affect_rows){
// insertLog('库存减少成功');
// }
?>
测试数据表
- --
- -- 数据库: `miaosha`
- --
-
- -- --------------------------------------------------------
-
- --
- -- 表的结构 `ih_goods`
- --
-
-
- CREATE TABLE IF NOT EXISTS `ih_goods` (
- `goods_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
- `cat_id` int(11) NOT NULL,
- `goods_name` varchar(255) NOT NULL,
- PRIMARY KEY (`goods_id`)
- ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;
-
-
- --
- -- 转存表中的数据 `ih_goods`
- --
-
-
- INSERT INTO `ih_goods` (`goods_id`, `cat_id`, `goods_name`) VALUES
- (1, 0, '小米手机');
-
- -- --------------------------------------------------------
-
- --
- -- 表的结构 `ih_log`
- --
-
- CREATE TABLE IF NOT EXISTS `ih_log` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `event` varchar(255) NOT NULL,
- `type` tinyint(4) NOT NULL DEFAULT '0',
- `addtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- PRIMARY KEY (`id`)
- ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
-
- --
- -- 转存表中的数据 `ih_log`
- --
-
-
- -- --------------------------------------------------------
-
- --
- -- 表的结构 `ih_order`
- --
-
- CREATE TABLE IF NOT EXISTS `ih_order` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `order_sn` char(32) NOT NULL,
- `user_id` int(11) NOT NULL,
- `status` int(11) NOT NULL DEFAULT '0',
- `goods_id` int(11) NOT NULL DEFAULT '0',
- `sku_id` int(11) NOT NULL DEFAULT '0',
- `price` float NOT NULL,
- `addtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='订单表' AUTO_INCREMENT=1 ;
-
- --
- -- 转存表中的数据 `ih_order`
- --
-
-
- -- --------------------------------------------------------
-
- --
- -- 表的结构 `ih_store`
- --
-
- CREATE TABLE IF NOT EXISTS `ih_store` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `goods_id` int(11) NOT NULL,
- `sku_id` int(10) unsigned NOT NULL DEFAULT '0',
- `number` int(10) NOT NULL DEFAULT '0',
- `freez` int(11) NOT NULL DEFAULT '0' COMMENT '虚拟库存',
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='库存' AUTO_INCREMENT=2 ;
-
- --
- -- 转存表中的数据 `ih_store`
- --
-
- INSERT INTO `ih_store` (`id`, `goods_id`, `sku_id`, `number`, `freez`) VALUES
- (1, 1, 11, 500, 0);