您的位置:首页 > 数据库 > Redis

PHP 利用redis List队列简单实现秒杀功能

2020-06-11 11:34 501 查看

一 生产者producer部分

 

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

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

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

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

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

 

生产者代码 producer.php:

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

 

 

 

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

 

 

二 消费者consumer部分

 

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

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

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

 

消费者代码 consumer.php

 

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

 

 

 

注: 执行完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;
[/code]

 

 

 

 

 

 

 

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: