zoukankan      html  css  js  c++  java
  • PHP+Redis 实例【一】点赞 + 热度 下篇

    这篇主要讲如何将数据保存回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 
     6 
     7 $rel = true;        //无限循环的变量
     8 $num = 0;            //用来没数据时的判断依据
     9 date_default_timezone_set("Asia/Shanghai"); 
    10 $now = date("Y-m-d H:i:s");        //当前时间
    11 //file log
    12 $txt = dirname(__DIR__)."/Script_Log/clickgood_log.txt";
    13 $output = new OutputLog();
    14 $test = $output->open($txt,"a+");
    15 
    16 while($rel)
    17 {
    18     $redis = new RedisCtrl();
    19 
    20     //开始干活
    21     if($num==0){
    22         //这里就是将信息输出到文件里记录,下面很多地方都是一样的。
    23         $text = "start ".$name."
    ";
    24         echo $text;
    25         $output->write($test,$text);
    26     }
    27 
    28     //获取备份队列的长度
    29     $copylistlength = $redis->llen("comment:uploadcopylist"); 
    30 
    31     //我这里展示的是第一数据回滚到mysql,小伙伴想批量回滚的,自己改装下就可以用了。
    32     //自己动手丰衣足食!
    33     if($copylistlength>1)
    34     {
    35         //由于是单一数据回滚,所以我要判断它是否超过我设定的值,小伙伴们最好也自己定一个阈值。
    36         //report error
    37         echo $now." ->false
    ";
    38         $rel = false;
    39         return;
    40     }
    41     else if($copylistlength==1)
    42     {
    43         //这里判断防止上次redis出现错误,导致数据没有及时回到mysql
    44         $data = $redis->rpop("comment:uploadcopylist");
    45         $rel = $redis->UpdateClickGoodDataToMysql($data);
    46         $text = $rel."
    ";
    47         echo $text;
    48         $output->write($test,$text);
    49     }
    50     else
    51     {
    52         //获取主要队列的长度
    53         $listlength = $redis->llen("comment:uploadlist");
    54         if ($listlength>0) {
    55             //使用之前说到的设计模式
    56             $data = $redis->rpoplpush("comment:uploadlist","comment:uploadcopylist");
    57 
    58             $rel = $redis->UpdateClickGoodDataToMysql($data);
    59             $text = $rel."
    ";
    60             echo $text;
    61             $output->write($test,$text);
    62         }else{
    63             // 队列为空
    64             // 打印关闭信息,这里的写法算是维持进程窗口不关闭,需要手动关闭
    65             // 如果想让它执行完自动关闭的,
    66             // 把下面改写成$rel = false;
    67             if($num<=3){
    68                 $text = $now." -> please close .
    ";
    69                 echo $text;
    70                 $output->write($test,$text);
    71                 $num++;
    72             }
    73             else
    74             {
    75                 $output->close($test);
    76             }
    77         }
    78     }
    79 
    80 }

    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 
    10     //Redis
    11     public function __construct()
    12     {
    13         $this->redis = new Redis();
    14         $this->redis->connect(self::$redisIp,self::$redisPort);
    15         $this->redis->auth(self::$redisPass);
    16     }
    17 
    18     public function llen($key)
    19     {
    20         $rel = $this->redis->llen($key);
    21         return $rel;
    22     }
    23 
    24     public function rpop($key)
    25     {
    26         $rel = $this->redis->rpop($key);
    27         return $rel;
    28     }
    29 
    30     public function rpoplpush($source,$destination)
    31     {
    32         $rel = $this->redis->rpoplpush($source,$destination);
    33         return $rel;
    34     }
    35 
    36     public function UpdateClickGoodDataToMysql($data)
    37     {
    38         //get id and time from redis list
    39         $result = json_decode($data,true);
    40         $id = $result['id'];
    41         $time = $result['time'];
    42         $arr = array();
    43 
    44         //like
    45         $like = $this->redis->zscore("comment:like",$id);
    46         $like = $like?$like:0;
    47         //hate
    48         $hate = $this->redis->zscore("comment:hate",$id);
    49         $hate = $hate?$hate:0;
    50 
    51         $sql = "update comment_info set like_count=".$like.", hate_count=".$hate." where id=".$id;
    52         $arr[] = $sql;
    53         //update sql
    54         $mysql = new MysqlCtrl();
    55         $mysql->saveMySQL($arr);
    56 
    57         //更新完,将set集合里需要更新的id去掉
    58         $this->redis->srem("comment:uploadset",$id);
    59         //更新完毕,将备份队列里的数据去掉
    60         $this->redis->lrem("comment:uploadcopylist",$data);
    61 
    62         return $sql."
    ";
    63     }
    64 }

    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 
    15     public $dsn = null;
    16     public $dbh = null;
    17 
    18     public function __construct()
    19     {
    20         $this->dsn = self::$dbms.":host=".self::$host.";dbname=".self::$database;
    21         //return $dsn;
    22         try {
    23               $this->dbh = new PDO($this->dsn, self::$user, self::$pass);
    24               echo "Connected
    ";
    25         } catch (Exception $e) {
    26             echo $this->dsn;
    27               die("Unable to connect: " . $e->getMessage());
    28         }
    29     }
    30     
    31     //保存数据到数据库
    32     //PDO
    33     public function saveMySQL($arr)
    34     {
    35 
    36         try {  
    37               $this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    38 
    39               $this->dbh->beginTransaction();
    40 
    41               $count = count($arr);
    42               for ($i=0; $i < $count; $i++) { 
    43                   $this->dbh->exec($arr[$i]);
    44               }
    45         
    46               $this->dbh->commit();
    47           
    48         } catch (Exception $e) {
    49               $this->dbh->rollBack();
    50               echo "Failed: " . $e->getMessage()."
    ";
    51               $json = json_encode($arr);
    52               echo "False-SQL: ".$json."
    ";
    53               exit();
    54         }
    55     }
    56 }

    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 
    10     public function write($name,$title)
    11     {
    12         $rel = fwrite($name, $title);
    13         return $rel;
    14     }
    15 
    16     public function close($name)
    17     {
    18         fclose($name);
    19     }
    20 }

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

    hellO world

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

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

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

    clickgood.bat:

     1 D:Softwarewamp64inphpphp7.0.10php.exe index.php 

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

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

    欢迎大家交流,上面只是本人自己的做法,希望大家能够指出错误的地方!或者提供更好的做法。

  • 相关阅读:
    Linux 关机和重启命令
    Linux ubuntu安装ftp服务器
    C++ map和unsorted_map底层实现
    C++中的那些容器在使用时,哪些情况下迭代器会失效
    虚函数表的构造
    C++容器 priority_queue,堆的实现
    c++11中的move是否会改变对象的地址
    (转)关于linux中内核编程中结构体的赋值操作(结构体指定初始化)
    无参方法
    类和对象
  • 原文地址:https://www.cnblogs.com/sunshine-H/p/7928034.html
Copyright © 2011-2022 走看看