欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-03-23 11:17:07
这篇主要讲如何将数据保存回Mysql,但是里面还会涉及到如何将错误信息以及提示信息保存到文件里,方便以后的运维,再有就是如何使用PHP写进程BAT。 Redis数据刷回数据库前的知识准备 首先针对上篇提到的关于redis刷回数据库的安全性的设计模式,因为我们使用的是list来做数据索引,所以在我们将 ......

这篇主要讲如何将数据保存回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."\n";
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\n";
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."\n";
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."\n";
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 .\n";
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."\n";
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\n";
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()."\n";
51               $json = json_encode($arr);
52               echo "False-SQL: ".$json."\n";
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:\Software\wamp64\bin\php\php7.0.10\php.exe index.php 

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

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

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