zoukankan      html  css  js  c++  java
  • 利用redis List队列简单实现秒杀 PHP代码实现

    利用redis List队列简单实现秒杀 PHP代码实现

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
    本文链接:https://blog.csdn.net/m_nanle_xiaobudiu/article/details/80479666

    一 生产者producer部分

    --------------------------------producer 部分注释------------------------------------------------------------

    用户在页面请求之后, 获取到用户uid , 跳转到这个加入队列的方法 (这里直接在producer中模拟了多个uid)

    在方法内部判断redis队列长度是否已经达到要求, 如果没有超出, 则执行加入队列的操作 (这里为了简洁,没有封装成方法)

    注: producer.php没有进行数据库的操作,只有接受uid和其他值的操作, 数据库操作一律放在消费者consumer.php中

    --------------------------------producer 注释结束-----------------------------------------------------------------------

    生产者代码 producer.php:

    1.  
      <?php
    2.  
       
    3.  
      //连接redis数据库
    4.  
      $redis = new Redis();
    5.  
      $redis->connect('127.0.0.1',6379);
    6.  
      $redis_name = 'secKill3';
    7.  
       
    8.  
      //模拟100人请求秒杀(高压力)
    9.  
      for ($i = 0; $i < 100; $i++) {
    10.  
      $uid = rand(10000000, 99999999);
    11.  
      //获取当前队列已经拥有的数量,如果人数少于十,则加入这个队列
    12.  
      $num = 10;
    13.  
      if ($redis->lLen($redis_name) < $num) {
    14.  
      $redis->rPush($redis_name, $uid);
    15.  
      echo $uid . "秒杀成功"."<br>";
    16.  
      } else {
    17.  
      //如果当前队列人数已经达到10人,则返回秒杀已完成
    18.  
      echo "秒杀已结束<br>";
    19.  
      }
    20.  
      }
    21.  
      //关闭redis连接
    22.  
      $redis->close();
    23.  
       

    注: 执行完producer.php文件,本地redis数据库第0号数据库中应该有一个键名为"secKill3"的List队列,像这样

    二 消费者consumer部分

    ------------------------------消费者部分注释---------------------------------------------

    消费者一直读取redis数据库中指定队列,一有值,立即取出,并进行相应数据库操作

    ------------------------------消费者部分注释结束----------------------------------------

    消费者代码 consumer.php

    1.  
      <?php
    2.  
       
    3.  
      //设置redis数据库连接及键名
    4.  
      $redis = new Redis();
    5.  
      $redis->connect('127.0.0.1');
    6.  
      $key = 'secKill3';//redis数据库key [注:默认redis数据库选择第0号数据库]
    7.  
       
    8.  
      //PDO连接mysql数据库
    9.  
      $dsn = "mysql:dbname=test;host=127.0.0.1";
    10.  
      $pdo = new PDO($dsn, 'root', '123456');
    11.  
       
    12.  
      //死循环
    13.  
      //从队列最前头取出一个值,判断这个值是否存在,取出时间和uid,保存到数据库
    14.  
      //数据库插入失败时,要有回滚机制
    15.  
      //注: rpush 和lpop是一对
    16.  
       
    17.  
      while(1) {
    18.  
      //从队列最前头取出一个值
    19.  
      $uid = $redis->lPop($key);
    20.  
      //判断值是否存在
    21.  
      if(!$uid || $uid == 'nil'){
    22.  
      sleep(2);
    23.  
      continue;
    24.  
      }
    25.  
      //生成订单号
    26.  
      $orderNum = build_order_no($uid);
    27.  
      //生成订单时间
    28.  
      $timeStamp = time();
    29.  
      //构造插入数组
    30.  
      $user_data = array('uid'=>$uid,'time_stamp'=>$timeStamp,'order_num'=>$orderNum);
    31.  
      //将数据保存到数据库
    32.  
      $sql = "insert into student (uid,time_stamp,order_num) values (:uid,:time_stamp,:order_num)";
    33.  
      $stmt = $pdo->prepare($sql);
    34.  
      $res = $stmt->execute($user_data);
    35.  
      //数据库插入数据失败,回滚
    36.  
      if(!$res){
    37.  
      $redis->rPush($key,$uid);
    38.  
      }
    39.  
      }
    40.  
       
    41.  
      //生成唯一订单号
    42.  
      function build_order_no($uid){
    43.  
      return substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8).$uid;
    44.  
      }

    注: 执行完consumer.php之后,数据库对应数据表应该有数值

    到此,秒杀结束

    备注:

    用到的student数据表结构sql

    1.  
      CREATE TABLE `student` (
    2.  
      `uid` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'uid',
    3.  
      `username` varchar(20) NOT NULL DEFAULT '',
    4.  
      `time_stamp` int(11) NOT NULL DEFAULT 0,
    5.  
      `order_num` bigint(20) UNSIGNED NOT NULL DEFAULT 0,
    6.  
      PRIMARY KEY (`uid`) USING BTREE,
    7.  
      key (time_stamp)
    8.  
      ) ENGINE = MyISAM default charset=utf8;
     
  • 相关阅读:
    PAT (Advanced Level) Practice 1100 Mars Numbers (20分)
    PAT (Advanced Level) Practice 1107 Social Clusters (30分) (并查集)
    PAT (Advanced Level) Practice 1105 Spiral Matrix (25分)
    PAT (Advanced Level) Practice 1104 Sum of Number Segments (20分)
    PAT (Advanced Level) Practice 1111 Online Map (30分) (两次迪杰斯特拉混合)
    PAT (Advanced Level) Practice 1110 Complete Binary Tree (25分) (完全二叉树的判断+分享致命婴幼儿错误)
    PAT (Advanced Level) Practice 1109 Group Photo (25分)
    PAT (Advanced Level) Practice 1108 Finding Average (20分)
    P6225 [eJOI2019]异或橙子 树状数组 异或 位运算
    P4124 [CQOI2016]手机号码 数位DP
  • 原文地址:https://www.cnblogs.com/guiyishanren/p/11563862.html
Copyright © 2011-2022 走看看