这篇主要讲如何将数据保存回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:

 <?php
require_once(__DIR__."/Mysql.class.php");
require_once(__DIR__."/Redis.class.php");
require_once(__DIR__."/Output_Log.class.php"); $rel = true; //无限循环的变量
$num = 0; //用来没数据时的判断依据
date_default_timezone_set("Asia/Shanghai");
$now = date("Y-m-d H:i:s"); //当前时间
//file log
$txt = dirname(__DIR__)."/Script_Log/clickgood_log.txt";
$output = new OutputLog();
$test = $output->open($txt,"a+"); while($rel)
{
$redis = new RedisCtrl(); //开始干活
if($num==0){
//这里就是将信息输出到文件里记录,下面很多地方都是一样的。
$text = "start ".$name."\n";
echo $text;
$output->write($test,$text);
} //获取备份队列的长度
$copylistlength = $redis->llen("comment:uploadcopylist"); //我这里展示的是第一数据回滚到mysql,小伙伴想批量回滚的,自己改装下就可以用了。
//自己动手丰衣足食!
if($copylistlength>1)
{
//由于是单一数据回滚,所以我要判断它是否超过我设定的值,小伙伴们最好也自己定一个阈值。
//report error
echo $now." ->false\n";
$rel = false;
return;
}
else if($copylistlength==1)
{
//这里判断防止上次redis出现错误,导致数据没有及时回到mysql
$data = $redis->rpop("comment:uploadcopylist");
$rel = $redis->UpdateClickGoodDataToMysql($data);
$text = $rel."\n";
echo $text;
$output->write($test,$text);
}
else
{
//获取主要队列的长度
$listlength = $redis->llen("comment:uploadlist");
if ($listlength>0) {
//使用之前说到的设计模式
$data = $redis->rpoplpush("comment:uploadlist","comment:uploadcopylist"); $rel = $redis->UpdateClickGoodDataToMysql($data);
$text = $rel."\n";
echo $text;
$output->write($test,$text);
}else{
// 队列为空
// 打印关闭信息,这里的写法算是维持进程窗口不关闭,需要手动关闭
// 如果想让它执行完自动关闭的,
// 把下面改写成$rel = false;
if($num<=3){
$text = $now." -> please close .\n";
echo $text;
$output->write($test,$text);
$num++;
}
else
{
$output->close($test);
}
}
} }

Redis.class.php:  redis操作类

 <?php
class RedisCtrl
{
//init redis
static $redisIp = "127.0.0.1";
static $redisPort =6379;
static $redisPass ="";
public $redis = null; //Redis
public function __construct()
{
$this->redis = new Redis();
$this->redis->connect(self::$redisIp,self::$redisPort);
$this->redis->auth(self::$redisPass);
} public function llen($key)
{
$rel = $this->redis->llen($key);
return $rel;
} public function rpop($key)
{
$rel = $this->redis->rpop($key);
return $rel;
} public function rpoplpush($source,$destination)
{
$rel = $this->redis->rpoplpush($source,$destination);
return $rel;
} public function UpdateClickGoodDataToMysql($data)
{
//get id and time from redis list
$result = json_decode($data,true);
$id = $result['id'];
$time = $result['time'];
$arr = array(); //like
$like = $this->redis->zscore("comment:like",$id);
$like = $like?$like:0;
//hate
$hate = $this->redis->zscore("comment:hate",$id);
$hate = $hate?$hate:0; $sql = "update comment_info set like_count=".$like.", hate_count=".$hate." where id=".$id;
$arr[] = $sql;
//update sql
$mysql = new MysqlCtrl();
$mysql->saveMySQL($arr); //更新完,将set集合里需要更新的id去掉
$this->redis->srem("comment:uploadset",$id);
//更新完毕,将备份队列里的数据去掉
$this->redis->lrem("comment:uploadcopylist",$data); return $sql."\n";
}
}

Mysql.class.php  mysql类

 <?php
//封装函数
class MysqlCtrl
{
//初始化参数
//数据库参数配置
static $dbms = "mysql";
static $host = Your host;
static $user = Your user;
static $pass = Your pass;
static $database = Your database;
//睡眠时间
static $sleep = 1; public $dsn = null;
public $dbh = null; public function __construct()
{
$this->dsn = self::$dbms.":host=".self::$host.";dbname=".self::$database;
//return $dsn;
try {
$this->dbh = new PDO($this->dsn, self::$user, self::$pass);
echo "Connected\n";
} catch (Exception $e) {
echo $this->dsn;
die("Unable to connect: " . $e->getMessage());
}
} //保存数据到数据库
//PDO
public function saveMySQL($arr)
{ try {
$this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $this->dbh->beginTransaction(); $count = count($arr);
for ($i=0; $i < $count; $i++) {
$this->dbh->exec($arr[$i]);
} $this->dbh->commit(); } catch (Exception $e) {
$this->dbh->rollBack();
echo "Failed: " . $e->getMessage()."\n";
$json = json_encode($arr);
echo "False-SQL: ".$json."\n";
exit();
}
}
}

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

 <?php
class OutputLog
{
public function open($name,$r)
{
$text = fopen($name, $r);
return $text;
} public function write($name,$title)
{
$rel = fwrite($name, $title);
return $rel;
} public function close($name)
{
fclose($name);
}
}

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

hellO world

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

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

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

clickgood.bat:

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

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

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

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

PHP+Redis 实例【一】点赞 + 热度 下篇的更多相关文章

  1. redis 实例2 构建文章投票网站后端

    redis 实例2 构建文章投票网站后端   1.限制条件 一.如果网站获得200张支持票,那么这篇文章被设置成有趣的文章 二.如果网站发布的文章中有一定数量被认定为有趣的文章,那么这些文章需要被设置 ...

  2. 基于redis实现的点赞功能设计思路详解

    点赞其实是一个很有意思的功能.基本的设计思路有大致两种, 一种自然是用mysql等 数据库直接落地存储, 另外一种就是利用点赞的业务特征来扔到redis(或memcache)中, 然后离线刷回mysq ...

  3. 一次线上redis实例cpu占用率过高问题优化(转)

    前情提要: 最近接了大数据项目的postgresql运维,刚接过来他们的报表系统就出现高峰期访问不了的问题,报表涉及实时数据和离线数据,离线读pg,实时读redis.然后自然而然就把redis也挪到我 ...

  4. 使用CacheCloud管理Redis实例

    转载来源:http://www.ywnds.com/?p=10610 一.CacheCloud是什么? 最近在使用CacheCloud管理Redis,所以简单说一下,这里主要说一下我碰到的问题.Cac ...

  5. python3.4学习笔记(二十五) Python 调用mysql redis实例代码

    python3.4学习笔记(二十五) Python 调用mysql redis实例代码 #coding: utf-8 __author__ = 'zdz8207' #python2.7 import ...

  6. Redis 实例排除步骤

    Redis 应用案例 - 在问题中不断成长 原创 2017-02-05 杜亦舒  本文翻译整理自 Andy Grunwald 发布的一篇文章,写的是作者所在公司使用 Redis 时遇到的问题,以及处理 ...

  7. 生产消费者模式与python+redis实例运用(中级篇)

    上一篇文章介绍了生产消费者模式与python+redis实例运用(基础篇),但是依旧遗留了一个问题,就是如果消费者消费的速度跟不上生产者,依旧会浪费我们大量的时间去等待,这时候我们就可以考虑使用多进程 ...

  8. 生产消费者模式与python+redis实例运用(基础篇)

    根据这个图,我们举个简单的例子:假如你去某个餐厅吃饭,点了很多菜,厨师要一个一个菜的做,一个厨师不可能同时做出所有你点的菜,于是你有两个选择:第一个,厨师把所有菜都上齐了,你才开始吃:还有一个选择,做 ...

  9. 一台机器上搭建多个redis实例的配置文件修改部分

    1.单个redis服务搭建请参考:redis服务搭建 2.一台Redis服务器,分成多个节点,每个节点分配一个端口(6380,6381…),默认端口是6379. 每个节点对应一个Redis配置文件,如 ...

随机推荐

  1. WPF 绑定密码

    我们发现我们无法绑定密码框的密码,PasswordBox 的 Password 不能绑定. 我们想做 MVVM ,我们需要绑定密码,不能使用前台 xaml.cs 监听 密码改变得到密码的值,传到 Vi ...

  2. MySQL存储过程/存储过程与自定义函数的区别

    语法: 创建存储过程: CREATE [definer = {user|current_user}] PROCEDURE sp_name ([ proc_parameter [,proc_parame ...

  3. (转)Java中使用正则表达式的一个简单例子及常用正则分享

    转自:http://www.jb51.net/article/67724.htm 这篇文章主要介绍了Java中使用正则表达式的一个简单例子及常用正则分享,本文用一个验证Email的例子讲解JAVA中如 ...

  4. 关于CSS 的position定位问题

    对于初学者来说,css的position定位问题是比较常见的.之前搞不清楚postion定位是怎么回事,排版一直歪歪斜斜的,老是排不好 css的定位一般来说,分为四种: position:static ...

  5. LeetCode 283. Move Zeroes (移动零)

    Given an array nums, write a function to move all 0's to the end of it while maintaining the relativ ...

  6. LeetCode 153. Find Minimum in Rotated Sorted Array (在旋转有序数组中找到最小值)

    Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. (i.e. ...

  7. LeetCode 152. Maximum Product Subarray (最大乘积子数组)

    Find the contiguous subarray within an array (containing at least one number) which has the largest ...

  8. Msys2配置总结

    一.MSYS2的MirrorList配置 1.修改msys2安装目录下的/etc/pacman.d文件夹里面的3个mirrorlist.*文件 [mirrorlist.mingw32] #中国科学技术 ...

  9. C++ 多态与虚函数

    1.多态的概念 由虚函数实现的动态多态性就是:同一类族中不同类的对象,对同一函数调用作出不同的响应. 先看下面这个简单的例子: #include<iostream> using std:: ...

  10. 通过对DAO层的封装减少数据库操作的代码量

     在学框架之前,写项目时总是要花大量的时间去写数据库操作层代码,这样会大大降低我们的效率,为了解决这个问题,我花了两天时间利用反射机制和泛型将DAO层进行了封装,这样我们只需要写sql语句,不需要再写 ...