ITPub博客

首页 > 应用开发 > IT综合 > PHP+Redis 实例【一】点赞 + 热度 下篇

PHP+Redis 实例【一】点赞 + 热度 下篇

IT综合 作者:hunter403 时间:2018-03-01 17:15:45 0 删除 编辑

这篇主要讲如何将数据保存回Mysql,但是里面还会涉及到如何将错误信息以及提示信息保存到文件里,方便以后的运维,再有就是如何使用PHP写进程BAT。

Redis数据刷回数据库前的知识准备

  首先针对上篇提到的关于redis刷回数据库的安全性的设计模式,因为我们使用的是list来做数据索引,所以在我们将list数据提取出来的时候,一旦redis在这时候出现异常,就会导致刚提取出来的数据丢失!有些小伙伴就说,丢失就丢失呗,才一点数据。但是我们做程序,就应该以严谨为基础,所以下面就来说下Redis List这位大佬给我们提供了什么帮助。

  •   Redis List -》RpopLpush()函数
  •        使用方法:RPOPLPUSH source destination
  •        说明:命令RPOPLPUSH在一个原子时间内,执行以下两个动作:①命令RPOPLPUSH在一个原子时间内,执行以下两个动作;②将source弹出的元素插入到列表destination,作为destination列表的的头元素。
  •        设计模式:

      Redis的列表经常被用作队列(queue),用于在不同程序之间有序地交换消息(message)。一个程序(称之为生产者,producer)通过LPUSH命令将消息放入队列中,而另一个程序(称之为消费者,consumer)通过RPOP命令取出队列中等待时间最长的消息。

    不幸的是,在这个过程中,一个消费者可能在获得一个消息之后崩溃,而未执行完成的消息也因此丢失。

    使用RPOPLPUSH命令可以解决这个问题,因为它在返回一个消息之余,还将该消息添加到另一个列表当中,另外的这个列表可以用作消息的备份表:假如一切正常,当消费者完成该消息的处理之后,可以用LREM命令将该消息从备份表删除。

Redis数据刷回数据库

方面文字太多?没关系。下面先来一段代码!我们的主体部分:

index.php:


点击(此处)折叠或打开

  1. <?php
  2. require_once(__DIR__."/Mysql.class.php");
  3. require_once(__DIR__."/Redis.class.php");
  4. require_once(__DIR__."/Output_Log.class.php");


  5. $rel = true; //无限循环的变量
  6. $num = 0; //用来没数据时的判断依据
  7. date_default_timezone_set("Asia/Shanghai");
  8. $now = date("Y-m-d H:i:s"); //当前时间
  9. //file log
  10. $txt = dirname(__DIR__)."/Script_Log/clickgood_log.txt";
  11. $output = new OutputLog();
  12. $test = $output->open($txt,"a+");

  13. while($rel)
  14. {
  15.     $redis = new RedisCtrl();

  16.     //开始干活
  17.     if($num==0){
  18.         //这里就是将信息输出到文件里记录,下面很多地方都是一样的。
  19.         $text = "start ".$name."\n";
  20.         echo $text;
  21.         $output->write($test,$text);
  22.     }

  23.     //获取备份队列的长度
  24.     $copylistlength = $redis->llen("comment:uploadcopylist");

  25.     //我这里展示的是第一数据回滚到mysql,小伙伴想批量回滚的,自己改装下就可以用了。
  26.     //自己动手丰衣足食!
  27.     if($copylistlength>1)
  28.     {
  29.         //由于是单一数据回滚,所以我要判断它是否超过我设定的值,小伙伴们最好也自己定一个阈值。
  30.         //report error
  31.         echo $now." ->false\n";
  32.         $rel = false;
  33.         return;
  34.     }
  35.     else if($copylistlength==1)
  36.     {
  37.         //这里判断防止上次redis出现错误,导致数据没有及时回到mysql
  38.         $data = $redis->rpop("comment:uploadcopylist");
  39.         $rel = $redis->UpdateClickGoodDataToMysql($data);
  40.         $text = $rel."\n";
  41.         echo $text;
  42.         $output->write($test,$text);
  43.     }
  44.     else
  45.     {
  46.         //获取主要队列的长度
  47.         $listlength = $redis->llen("comment:uploadlist");
  48.         if ($listlength>0) {
  49.             //使用之前说到的设计模式
  50.             $data = $redis->rpoplpush("comment:uploadlist","comment:uploadcopylist");

  51.             $rel = $redis->UpdateClickGoodDataToMysql($data);
  52.             $text = $rel."\n";
  53.             echo $text;
  54.             $output->write($test,$text);
  55.         }else{
  56.             // 队列为空
  57.             // 打印关闭信息,这里的写法算是维持进程窗口不关闭,需要手动关闭
  58.             // 如果想让它执行完自动关闭的,
  59.             // 把下面改写成$rel = false;
  60.             if($num<=3){
  61.                 $text = $now." -> please close .\n";
  62.                 echo $text;
  63.                 $output->write($test,$text);
  64.                 $num++;
  65.             }
  66.             else
  67.             {
  68.                 $output->close($test);
  69.             }
  70.         }
  71.     }

  72. }

Redis.class.php:  redis操作类

点击(此处)折叠或打开

  1. <?php
  2. class RedisCtrl
  3. {
  4.     //init redis
  5.     static $redisIp = "127.0.0.1";
  6.     static $redisPort =6379;
  7.     static $redisPass ="";
  8.     public $redis = null;

  9.     //Redis
  10.     public function __construct()
  11.     {
  12.         $this->redis = new Redis();
  13.         $this->redis->connect(self::$redisIp,self::$redisPort);
  14.         $this->redis->auth(self::$redisPass);
  15.     }

  16.     public function llen($key)
  17.     {
  18.         $rel = $this->redis->llen($key);
  19.         return $rel;
  20.     }

  21.     public function rpop($key)
  22.     {
  23.         $rel = $this->redis->rpop($key);
  24.         return $rel;
  25.     }

  26.     public function rpoplpush($source,$destination)
  27.     {
  28.         $rel = $this->redis->rpoplpush($source,$destination);
  29.         return $rel;
  30.     }

  31.     public function UpdateClickGoodDataToMysql($data)
  32.     {
  33.         //get id and time from redis list
  34.         $result = json_decode($data,true);
  35.         $id = $result['id'];
  36.         $time = $result['time'];
  37.         $arr = array();

  38.         //like
  39.         $like = $this->redis->zscore("comment:like",$id);
  40.         $like = $like?$like:0;
  41.         //hate
  42.         $hate = $this->redis->zscore("comment:hate",$id);
  43.         $hate = $hate?$hate:0;

  44.         $sql = "update comment_info set like_count=".$like.", hate_count=".$hate." where id=".$id;
  45.         $arr[] = $sql;
  46.         //update sql
  47.         $mysql = new MysqlCtrl();
  48.         $mysql->saveMySQL($arr);

  49.         //更新完,将set集合里需要更新的id去掉
  50.         $this->redis->srem("comment:uploadset",$id);
  51.         //更新完毕,将备份队列里的数据去掉
  52.         $this->redis->lrem("comment:uploadcopylist",$data);

  53.         return $sql."\n";
  54.     }
  55. }

Mysql.class.php  mysql类

点击(此处)折叠或打开

  1. <?php
  2. //封装函数
  3. class MysqlCtrl
  4. {
  5.     //初始化参数
  6.     //数据库参数配置
  7.     static $dbms = "mysql";
  8.     static $host = Your host;
  9.     static $user = Your user;
  10.     static $pass = Your pass;
  11.     static $database = Your database;
  12.     //睡眠时间
  13.     static $sleep = 1;

  14.     public $dsn = null;
  15.     public $dbh = null;

  16.     public function __construct()
  17.     {
  18.         $this->dsn = self::$dbms.":host=".self::$host.";dbname=".self::$database;
  19.         //return $dsn;
  20.         try {
  21.               $this->dbh = new PDO($this->dsn, self::$user, self::$pass);
  22.               echo "Connected\n";
  23.         } catch (Exception $e) {
  24.             echo $this->dsn;
  25.               die("Unable to connect: " . $e->getMessage());
  26.         }
  27.     }
  28.     
  29.     //保存数据到数据库
  30.     //PDO
  31.     public function saveMySQL($arr)
  32.     {

  33.         try {
  34.               $this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

  35.               $this->dbh->beginTransaction();

  36.               $count = count($arr);
  37.               for ($i=0; $i < $count; $i++) {
  38.                   $this->dbh->exec($arr[$i]);
  39.               }
  40.         
  41.               $this->dbh->commit();
  42.           
  43.         } catch (Exception $e) {
  44.               $this->dbh->rollBack();
  45.               echo "Failed: " . $e->getMessage()."\n";
  46.               $json = json_encode($arr);
  47.               echo "False-SQL: ".$json."\n";
  48.               exit();
  49.         }
  50.     }
  51. }

Output_Log.class.php  输出信息到文件的类

点击(此处)折叠或打开

  1. <?php
  2. class OutputLog
  3. {
  4.     public function open($name,$r)
  5.     {
  6.         $text = fopen($name, $r);
  7.         return $text;
  8.     }

  9.     public function write($name,$title)
  10.     {
  11.         $rel = fwrite($name, $title);
  12.         return $rel;
  13.     }

  14.     public function close($name)
  15.     {
  16.         fclose($name);
  17.     }
  18. }

clickgood_log.txt  这里是保存输出的信息,里面是空白的。
hellO world

上面这些就是整套数据保存到mysql的操作,这是本人源码copy过来的,所以细分程度比较高,但是可扩展性也很高。有什么错误的地方希望小伙伴们能提出,谢谢。

最后就是我们的进程调用了,其实很简单

创建一个txt文件,然后改名为clickgood.bat,记得把txt后缀文件名改为bat

clickgood.bat:

 1 D:\Software\wamp64\bin\php\php7.0.10\php.exe index.php 

关于上面的bat注意两点,一前面那个php.exe,按照你自己的路径去找,我使用wampserver测试环境,基本就是上面的路径。第二点,后面的index.php和clickgood.bat同一目录下。

好了!终于可以收尾了!、


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/303827/viewspace-2151416/ ,如需转载,请注明出处,否则将追究法律责任。

下一篇: PHP操作redis
请登录后发表评论 登录
全部评论

注册时间:2009-06-03

  • 博文量
    10
  • 访问量
    25789