NoSQL(Redis)秒杀

NoSQL(Redis)秒杀

概念

秒杀
说明:秒杀就是指商家的限时大甩卖(商家为了售卖商品所采取的一种销售手段)
特征:1-限时,2-低价
种类:一元秒杀、低价限量秒杀、低价限时限量秒杀
好处:因为秒杀产品参与者数量众多,可以瞬间聚集人气,提升品牌影响力,是一种不错的促销手段。
并发
生活中:指同时有n个用户一起去收营台结账的表现可以称之为并发
网络中:指同时有n个用户一起访问网站的表现可以称之为并发
并发导致的问题:
生活中-忙不过来,程序中-服务器可能崩溃或者出现意外结果(负库存)
    在计算机中:通过消息队列实现

MySQL负库存(秒杀可能出现的问题)

修改mysql.ini max_connections = 10 #声明同时支持多少个用户连接

打开 navicat.exe 执行sql语句

create database if not exists miaosha charset=utf8;
use miaosha;
create table goods (id int primary key auto_increment,num int) engine=innodb;
insert into goods values (null, 100);

在站点目录下创建mysql.php输入下述命令

<?php
#语法:ab -n 1000 -c 100 请求地址
#说明:n-请求总数, c- 每次请求量

//1.创建PDO对象
$pdo = new PDO('mysql:dbname=miaosha', 'root', 'root');

//2.查询库存
$pdoStatement = $pdo->query('select num from goods where id = 1');
$res = $pdoStatement->fetch(PDO::FETCH_ASSOC);
$num = $res['num'];

//3.判断库存
if ($num) {
    //减库存
    $pdo->exec('update goods set num=num-1 where id = 1');
    echo '抢购成功';
} else {
    echo '对不起,你来晚了,库存不足';
}

通过本地Apache安装目录下bin目录中的ab测压工具测试并发

ab.exe -n 1000 -c 100 http://127.0.0.1/mysql.php

多测试几次 查看数据库 可能会出现负库存 这些是并发量高,数据处理不过来,当前面用户下单时,后面用户也读取到了库存数据 就会出现负库存

Redis消息队列(解决秒杀问题)

使用Workerman框架

下载Workerman框架....

在站点目录下创建testworkerman.php输入手册中的定时器代码

<?php  
use \Workerman\Worker;
use \Workerman\Lib\Timer;
require_once __DIR__ . '/Workerman/Autoloader.php';

$task = new Worker();
// 开启多少个进程运行定时任务,注意业务是否在多进程有并发问题
$task->count = 1;
$task->onWorkerStart = function($task)
{
    // 每2.5秒执行一次
    $time_interval = 2.5;
    Timer::add($time_interval, function()
    {
        echo "task run\n";
    });
};

// 运行worker
Worker::runAll();

打开DOS窗口通过php.exe执行testworkerman.php文件查看效果

实现

登录redis设置存放商品秒杀数据信息

    flushall
    hmset goods_seckill_1 start_time 0 stop_time 0 price 30 real_num 3 seckill_num 3
    hmset goods_seckill_2 start_time 0 stop_time 0 price 30 real_num 2 seckill_num 2

在站点目录下创建redis.php输入下述命令

<?php
#步骤1:接受数据
$uid = 1;
$goods_id = 1;

#步骤2:连接Redis
$redis = new Redis;
$redis->connect('192.168.159.128', 6379);
$redis->auth('123');
$redis->select(0);

#步骤3:过滤(判断时间和库存)
//获取商品信息
$goodsInfo = $redis->hmget("goods_seckill_{$goods_id}"., array(
    'start_time', 'stop_time', 'real_num', 'seckill_num', 'price'
));
//判断是否开始
//判断是否结束
//判断库存
if ($goodsInfo['seckill_num'] < 1) {
    echo json_encode(array('state' => 0, '对不起,宝贝已被抢完!'));
    die;
}

#步骤4:将用户请求加入消息队列中
$len = $redis->lpush("goods_seckill_{$goods_id}_rs", $uid.'%'.$goods_id.'%'.$goodsInfo['price']);

#步骤5:判断库存(规则:队列中前n个抢购成功)
if ($len > $goodsInfo['real_num']) {
//抢购失败(队列长度 > 库存)
    echo json_encode(array('state' => 0, '对不起,宝贝已被抢完!'));
    die;
} else {
//抢购成功,减库存(注:千万不能直接操作mysql因为有并发限制)
    echo json_encode(array('state' => 1, '秒杀成功'));
    die;
}

在站点目录创建workerman.php输入下述命令

<?php
use \Workerman\Worker;
use \Workerman\Lib\Timer;
require_once __DIR__ . '/Workerman/Autoloader.php';

$task = new Worker();
// 开启多少个进程运行定时任务,注意业务是否在多进程有并发问题
$task->count = 1;
$task->onWorkerStart = function($task)
{
    //每0.1秒执行一次(精度可以达到毫秒0.001)
    $time_interval = 0.1; 
    Timer::add($time_interval, function()
    {
        $goods_id = 1;
        #步骤1:连接Redis
        $redis = new Redis;
        $redis->connect('192.168.159.128', 6379);
        $redis->auth('123');
        $redis->select(0);
        #步骤2:获取秒杀相关信息
        $allowBuyNum = $redis->hget("goods_seckill_{$goods_id}", 'seckill_num'); //秒杀剩余库存
        $orderInfoString = $redis->rpop("goods_seckill_{$goods_id}_rs");                     //队列抢购用户信息
        #步骤3:判断(有库存 && 有人抢购)
        if($allowBuyNum > 0 && $orderInfoString) 
        {
            echo "allowBuyNum:$allowBuyNum\n";

            #步骤4:减库存
            $redis->hincrby('goods_seckill_1', 'seckill_num', -1);
            #步骤5:生成订单
            $pdo = new \PDO('mysql:dbname=php15shop', 'root', 'root');

            $userOrderInfo = explode('%', $orderInfoString); //$uid.'%'.$goods_id.'%'.$price
                $order_id = date('Ymd').time().uniqid();
                $total_price = $userOrderInfo[2];
                $member_id = $userOrderInfo[0];
                $goods_id = $userOrderInfo[1];
                $create_time = time();
                $update_time = time();
                #主表(sh_order)
                $sql = "insert into sh_order (order_id, total_price, member_id, create_time, update_time)
                value 
                ('{$order_id}', $total_price, $member_id, $create_time, $update_time)";
                $pdo->exec($sql);
                #从表(sh_order_goods)
                $sql = "insert into sh_order_goods (order_id, goods_id, goods_number, goods_price) value('{$order_id}', $goods_id , $total_price, 2)";
                $pdo->exec($sql);
                
            echo "over...\n";
        }
    });
};

// 运行worker
Worker::runAll();

通过DOS窗口运行workerman.php文件,监听队列数据

通过本地Apache安装目录下的bin目录ab测压工具测试并发

ab -n 1000 -c 100 http://127.0.0.1/redis2/redis.php

查看主表数据...

搭建秒杀项目虚拟主机

创建虚拟目录seckill

将seckill项目解压到站点目录中

打开seckill站点目录并修改数据库信息

将之前的shop商城数据复制一份 创建新数据库并修改sh_goods表增加字段is_seckill(是否秒杀商品)

在Admin后台创建Goods控制器seckillConfig方法

//商品秒杀配置
public function seckillConfig()
{   
    #步骤2:加载视图
    return $this->fetch('');
}

创建视图文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>商品秒杀配置</title>
</head>
<body>
    <form action="" method="post">
        <p>秒杀开始时间<input type="text" name="start_time" /></p>
        <p>秒杀结束时间<input type="text" name="stop_time" /></p>
        <p>秒杀价格<input type="text" name="price" /></p>
        <p>秒杀数量<input type="text" name="num" /></p>
        <p><input type="submit" value="提交"></p>
    </form>
</body>
</html>

数据处理:修改商品状态为秒杀 将秒杀商品数据保存的redis中

redis键规则:
hmset goods_seckill_1 start_time 0 stop_time 0 price 30 real_num 3 seckill_num 3

<a href="{:url('admin/goods/seckillConfig', array('goods_id' => $list['goods_id']))}" 
class="showContent tablelink">
    秒杀商品配置
</a>

修改admin后台的goods控制器sekillconfig方法进行数据处理

  public function seckillConfig()
    {   
        #步骤1:判断是否post提交
        if (request()->isPost()) {
            #步骤2:接受数据
            $start_time = input('start_time');
            $stop_time = input('stop_time');
            $price = input('price');
            $num = input('num');
            $goods_id = input('goods_id');
            #步骤3:插入数据
            $redis = new \Redis;
            $redis->connect('192.168.159.128', 6379);
            $redis->auth('123');
            #hmset 键  字段1 值1 ... 字段n 值n
            #hmset goods_seckill_1 start_time 0 stop_time 0 price 30 real_num 3 seckill_num 3
            $tempData = array(
                'start_time' => $start_time,
                'stop_time' => $stop_time,
                'price' => $price,
                'real_num' => $num,
                'seckill_num' => $num,
            );
            $rs = $redis -> hMset('goods_seckill_'.$goods_id, $tempData);
            #步骤4:判断
            if ($rs) {
                #修改商品状态为秒杀
                Goods::where('goods_id', $goods_id)->update([
                    'is_seckill' => 1
                ]);
                #跳转到商品秒杀列表页
                $this->success("商品秒杀配置成功", url("admin/goods/seckill"));
            }else{
                $this->error("商品秒杀配置失败");
            }
        } else {
            #步骤2:加载视图
            return $this->fetch('');
        }
    }

整合日期插件

下载jq插件包放到查念public/plugin目录好

商品秒杀页配置引入

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>商品秒杀配置</title>
</head>
<body>
    <form action="" method="post">
        <p>秒杀开始时间
            <input type="text" name="start_time" 
                onClick="WdatePicker({el:this,dateFmt:'yyyy-MM-dd HH:mm:ss'})" 
                autocomplete="off"
            />
        </p>
        <p>
            秒杀结束时间<input type="text" name="stop_time" 
                onClick="WdatePicker({el:this,dateFmt:'yyyy-MM-dd HH:mm:ss'})" 
                autocomplete="off"
            />
        </p>
        <p>秒杀价格<input type="text" name="price" /></p>
        <p>秒杀数量<input type="text" name="num" /></p>
        <p><input type="submit" value="提交"></p>
    </form>

    <script language="javascript" type="text/javascript" src="/plugin/My97DatePicker/WdatePicker.js"></script>
</body>
</html>

修改控制器方法格式化日期

start_time => strtltime($start_time)
stop_time => strtotime($stop_time)

在Admin后台创建Goods控制器seckill方法

public function seckill()
{
    #步骤1:查询所有数据
    $seckills = Goods::where('is_seckill', 1)->select();
    #步骤2:过滤数据
    foreach ($seckills as $seckill) {
        #$seckill->goods_id
        #$seckill->goods_name
        #查询商品秒杀信息
        $redis = new \Redis;
        $redis->connect('192.168.159.128', 6379);
        $redis->auth('123');
        $temp = $redis -> hMget('goods_seckill_'.$seckill->goods_id, array(
            'start_time',
            'stop_time',
            'price',
            'real_num'
        ));
        #将商品秒杀信息添加到$seckill中
        $seckill->start_time = $temp['start_time'];
        $seckill->stop_time = $temp['stop_time'];
        $seckill->price = $temp['price'];
        $seckill->real_num = $temp['real_num'];
    }
    #步骤3:加载视图
    return $this->fetch('', [
        'seckills'=>$seckills
    ]);
}

创建视图并循环显示数据

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <table border="1" cellpadding="10" cellspacing="0">
        <tr>
            <td>商品ID</td>
            <td>商品名称</td>
            <td>商品价格</td>
            <td>商品数量</td>
            <td>开始时间</td>
            <td>结束时间</td>
            <td>距离结束</td>
        </tr>
        {foreach $seckills as $seckill}
        <tr>
            <td>{$seckill.goods_id}</td>
            <td>{$seckill.goods_name}</td>
            <td>{$seckill.price}</td>
            <td>{$seckill.real_num}</td>
            <td>{:date('Y-m-d H:i:s', $seckill.start_time)}</td>
            <td>{:date('Y-m-d H:i:s', $seckill.stop_time)}</td>
            <td>0</td>
        </tr>
        {/foreach}
    </table>
</body>
</html>

距离倒计时(修改控制器 ) 增加字段

$seckill->time = $temp['stop_time']

距离倒计时(修改视图)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script type="text/javascript" src="{:config('admin_static')}/js/jquery.js"></script>
    <script>
    function timer(intDiff,idName) {
        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;

            $(idName).html(day + "天" + hour + '时' + minute + '分' + second + '秒');

            //console.log(idName);
            //$(idName+' .day_show').html(day + "天");
            //$(idName+' .hour_show').html('<s id="h"></s>' + hour + '时');
            //$(idName+' .minute_show').html('<s></s>' + minute + '分');
            //$(idName+' .second_show').html('<s></s>' + second + '秒');
            intDiff--;
        }, 1000);
    }
    </script>
</head>
<body>

    <table border="1" cellpadding="10" cellspacing="0">
        <tr>
            <td>商品ID</td>
            <td>商品名称</td>
            <td>商品价格</td>
            <td>商品数量</td>
            <td>开始时间</td>
            <td>结束时间</td>
            <td>距离结束</td>
        </tr>
        {foreach $seckills as $seckill}
        <tr>
            <td>{$seckill.goods_id}</td>
            <td>{$seckill.goods_name}</td>
            <td>{$seckill.price}</td>
            <td>{$seckill.real_num}</td>
            <td>{:date('Y-m-d H:i:s', $seckill.start_time)}</td>
            <td>{:date('Y-m-d H:i:s', $seckill.stop_time)}</td>
            <td id="time{$seckill.goods_id}">0</td>
        </tr>
        <script>
         timer({$seckill->time},'#time{$seckill.goods_id}');
        </script>
        {/foreach}
    </table>
</body>
</html>

完成前台秒杀功能

修改home/index/index

<li><a href="{:url('home/seckill/index')}">商品秒杀</a></li>

在后台创建seckill控制器index方法

<?php
namespace app\home\controller;
use think\Controller;
use app\home\model\Goods;

class SeckillController extends Controller
{
    public function index()
    {
      #步骤1:查询所有数据
      $seckills = Goods::where('is_seckill', 1)->select();
      #步骤2:过滤数据
      foreach ($seckills as $seckill) {
          #$seckill->goods_id
          #$seckill->goods_name
          #查询商品秒杀信息
          $redis = new \Redis;
          $redis->connect('192.168.159.128', 6379);
          $redis->auth('123');
          $temp = $redis -> hMget('goods_seckill_'.$seckill->goods_id, array(
              'start_time',
              'stop_time',
              'price',
              'real_num',
              'seckill_num',
          ));
          #将商品秒杀信息添加到$seckill中
          $seckill->start_time = $temp['start_time'];
          $seckill->stop_time = $temp['stop_time'];
          $seckill->price = $temp['price'];
          $seckill->real_num = $temp['real_num'];
          $seckill->seckill_num = $temp['seckill_num'];
      }
      #步骤3:加载视图
      return $this->fetch('', [
          'seckills'=>$seckills
      ]);
    }
}

创建视图并循环显示数据

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>一元秒杀!还包邮!</title>
<style type="text/css">
*{margin:0; padding:0;}
body{font-family:"微软雅黑";}
.html{ overflow:auto}
.c{ clear:both;}
a{text-decoration: NONE; color:#000; font-size:16px;}
.bodybg{ background:url({:config('home_static')}/image/bg.jpg); width:100%;}
.banner{ background:url({:config('home_static')}/image/banner.jpg) no-repeat center; height:542px;}
.nav{ border:none;width:1000px;margin:0 auto;}
.probg{ background:#f4ad1e; width:1000px; margin:0 auto; text-align:center;}
.fl{ float:left; padding-left:9px; padding-top:9px;}
.onebg{ width:321px; height:321px; background:#FFF;}
.titlebg{ width:321px; height:33px; background:#FFF;}
.buybg{ background:url({:config('home_static')}/image/pricebg.jpg); width:321px; height:70px;} 
.foreprice{ font-size:17px; text-decoration:line-through; color:#FFF;float:left; padding-top:13px; padding-left:25px;}
.button{ width:96px;height:70px;float:right; padding:0;}
.ads{ width:1000px; height:326px; margin:0 auto;}
.sm{ background:#FFF; width:100%; margin:0 auto;}
.xize{ width:1000px; margin:0 auto; text-align:left; font-size:36px; font-weight:700; color:#9E051A;}
.shuoming{ width:1000px; margin:0 auto; text-align:left; font-size:20px;color:#9E051A; line-height:35px;}
</style>
</head>

<body>
    <div class="banner"></div>
    <div class="bodybg">
            <div class="nav"><img src="{:config('home_static')}/image/nav.jpg" width="1000" height="70"/></div>
            <div class="probg"> 

           {foreach $seckills as $seckill}
             <!-- 单个商品循环-->
              <div class="fl">
                <div class="onebg"  >
                <a href="javascript:void(0);" ><img src="{:config('home_static')}/image/1.jpg" width="321px;height:321px"/></a>
                </div> 
                <div class="titlebg">
                <a href="javascript:void(0);" >{$seckill.goods_name}</a>
                </div>
                <div class="buybg" style="background: red;">
                <div class="foreprice" style="text-decoration:none;">价格:{$seckill.price}</div>
                <div class="foreprice" style="text-decoration:none;">库存:{$seckill.seckill_num}</div>
                <div class="button">
                    <!-- <img src="{:config('home_static')}/image/button.jpg"/> -->
                    <input type="button" value="立即抢购"  style="margin-top:20px; width: 80px;height: 30px; cursor: pointer;" data-id="{$seckill.goods_id}"/>
                  </div>        
                </div>
              </div>
              <!-- 单个商品循环结束-->
           {/foreach}

              <div>
                <a href="javascript:void(0);" ><img src="{:config('home_static')}/image/ads.jpg" /></a>
              </div>
              
              <div class="c"></div>                      
         </div> 
         <div class="sm">
         <br />
             <div class="xize">1元秒杀细则:</div>
            <div class="shuoming">1.参与秒杀前,请详细阅读秒杀规则,凡参与1元秒杀活动的用户,均视为同意秒杀规则。<br />2.秒杀商品将于2014年7月7日08:00:00上线-2014年7月11日23:59:59结束,当天商品售罄时当天秒杀结束,活动期间每一个云中央注册会员每期仅限秒杀一个商品,秒杀多件成功者,并通过收货人及联系方式可判定为同一人的,则取消全部订单。<br />3.秒杀成功以支付成功为准,早秒早得;秒杀下单后30分钟内未付款者自动取消订单,请特别注意。<br />4.请确保秒杀填写的收货人信息真实有效,因联系方式填写错误导致未收到礼品的,由用户自行承担损失。<br />5.对于任何通过不正当手段参与秒杀者,不正当手段包括但不限于使用秒杀器或类似作弊软件,云中央网站有权依据自身技术判断,并在不事先通知的情况下取消其秒杀资格或者取消订单。
             </div>
         </div>
    </div>
</body>
</html>

立即抢购(入队)

在home/平台创建Seckill控制器创建add方法

public function add()
{
    #步骤1:接受数据
    $uid = session('member_id');
    if(!$uid) {
      echo json_encode(array('state' => 0, 'msg'=>'请登录后重试...'));
      die;
    };
    $goods_id = input('goods_id');
    if(!$goods_id) {
      echo json_encode(array('state' => 0, 'msg'=>'非法操作...'));
      die;
    }

    #步骤2:连接Redis
    $redis = new \Redis;
    $redis->connect('192.168.159.128', 6379);
    $redis->auth('123');
    $redis->select(0);

    #步骤3:过滤(判断时间和库存)
    //获取商品信息
    $goodsInfo = $redis->hmget("goods_seckill_{$goods_id}", array(
      'start_time', 'stop_time', 'real_num', 'seckill_num', 'price'
    ));
    if(!$goodsInfo) {
      echo json_encode(array('state' => 0, 'msg'=>'秒杀商品不存在...'));
      die;
    }
    //判断是否开始
    if ($goodsInfo['start_time'] > time()) {
      echo json_encode(array('state' => 0, 'msg'=>'未开始'));
      die;
    }
    //判断是否结束
    if ($goodsInfo['stop_time'] < time()) {
      echo json_encode(array('state' => 0, 'msg'=>'已结束'));
      die;
    }
    //判断库存
    if ($goodsInfo['seckill_num'] < 1) {
      echo json_encode(array('state' => 0, 'msg'=>'对不起,宝贝已被抢完!'));
      die;
    }

    #步骤4:将用户请求加入消息队列中
    $len = $redis->lpush("goods_seckill_{$goods_id}_rs", $uid.'%'.$goods_id.'%'.$goodsInfo['price']);

    #步骤5:判断库存(规则:队列中前n个抢购成功)
    if ($len > $goodsInfo['real_num']) {
    //抢购失败(队列长度 > 库存)
      echo json_encode(array('state' => 0, 'msg'=>'对不起,宝贝已被抢完!'));
      die;
    } else {
    //抢购成功,减库存(注:千万不能直接操作mysql因为有并发限制)
      echo json_encode(array('state' => 1, 'msg'=>'秒杀成功'));
      die;
    }
}

修改秒杀列表发送异步请求

<script type="text/javascript" src="{:config('home_static')}/js/jquery-1.8.3.min.js"></script>
<script> 
$(function(){
    $('.buybg input').click(function(){
         //禁用按钮
         var thisObj = $(this);
         $(this).attr('disabled', 'disabled');
         $(this).css('cursor', 'default');
         $(this).val('抢购中...');

         var goods_id = $(this).attr('data-id');
         $.post("{:url('home/seckill/add')}", {goods_id:goods_id},function(data){
              if (data.state) {
                alert(data.msg);
                location.href = "{:url('home/order/seckill')}";
              } else {
                alert(data.msg)
              }

              //还原按钮
             $(thisObj).removeAttr('disabled');
             $(thisObj).css('cursor', 'pointer');
             $(thisObj).val('立即抢购');

         }, 'json');

    });
});
</script>

使用Workerman框架(出队)

<?php
use \Workerman\Worker;
use \Workerman\Lib\Timer;
require_once __DIR__ . '/Workerman/Autoloader.php';

$task = new Worker();
// 开启多少个进程运行定时任务,注意业务是否在多进程有并发问题
$task->count = 1;
$task->onWorkerStart = function($task)
{
    //每0.1秒执行一次(精度可以达到毫秒0.001)
    $time_interval = 0.1; 
    Timer::add($time_interval, function()
    {
        $goods_id = 9;
        #步骤1:连接Redis
        $redis = new Redis;
        $redis->connect('192.168.159.128', 6379);
        $redis->auth('123');
        $redis->select(0);
        #步骤2:获取秒杀相关信息
        $allowBuyNum = $redis->hget("goods_seckill_{$goods_id}", 'seckill_num'); //秒杀剩余库存
        $orderInfoString = $redis->rpop("goods_seckill_{$goods_id}_rs");                     //队列抢购用户信息
        #步骤3:判断(有库存 && 有人抢购)
        if($allowBuyNum > 0 && $orderInfoString) 
        {
            echo "allowBuyNum:$allowBuyNum\n";

            #步骤4:减库存
            $redis->hincrby('goods_seckill_1', 'seckill_num', -1);
            #步骤5:生成订单
            $pdo = new \PDO('mysql:dbname=seckill', 'root', 'root');

            $userOrderInfo = explode('%', $orderInfoString); //$uid.'%'.$goods_id.'%'.$price
                $order_id = date('Ymd').time().uniqid();
                $total_price = $userOrderInfo[2];
                $member_id = $userOrderInfo[0];
                $goods_id = $userOrderInfo[1];
                $create_time = time();
                $update_time = time();
                #主表(sh_order)
                $sql = "insert into sh_order (is_seckill, order_id, total_price, member_id, create_time, update_time)
                value 
                (1, '{$order_id}', $total_price, $member_id, $create_time, $update_time)";
                $pdo->exec($sql);
                #从表(sh_order_goods)
                $sql = "insert into sh_order_goods (order_id, goods_id, goods_number, goods_price) value('{$order_id}', $goods_id, 1, $total_price)";
                $pdo->exec($sql);
                
            echo "over...\n";
        }
    });
};

// 运行worker
Worker::runAll();
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容