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:
<?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 实例【一】点赞 + 热度 下篇的更多相关文章
- redis 实例2 构建文章投票网站后端
redis 实例2 构建文章投票网站后端 1.限制条件 一.如果网站获得200张支持票,那么这篇文章被设置成有趣的文章 二.如果网站发布的文章中有一定数量被认定为有趣的文章,那么这些文章需要被设置 ...
- 基于redis实现的点赞功能设计思路详解
点赞其实是一个很有意思的功能.基本的设计思路有大致两种, 一种自然是用mysql等 数据库直接落地存储, 另外一种就是利用点赞的业务特征来扔到redis(或memcache)中, 然后离线刷回mysq ...
- 一次线上redis实例cpu占用率过高问题优化(转)
前情提要: 最近接了大数据项目的postgresql运维,刚接过来他们的报表系统就出现高峰期访问不了的问题,报表涉及实时数据和离线数据,离线读pg,实时读redis.然后自然而然就把redis也挪到我 ...
- 使用CacheCloud管理Redis实例
转载来源:http://www.ywnds.com/?p=10610 一.CacheCloud是什么? 最近在使用CacheCloud管理Redis,所以简单说一下,这里主要说一下我碰到的问题.Cac ...
- python3.4学习笔记(二十五) Python 调用mysql redis实例代码
python3.4学习笔记(二十五) Python 调用mysql redis实例代码 #coding: utf-8 __author__ = 'zdz8207' #python2.7 import ...
- Redis 实例排除步骤
Redis 应用案例 - 在问题中不断成长 原创 2017-02-05 杜亦舒 本文翻译整理自 Andy Grunwald 发布的一篇文章,写的是作者所在公司使用 Redis 时遇到的问题,以及处理 ...
- 生产消费者模式与python+redis实例运用(中级篇)
上一篇文章介绍了生产消费者模式与python+redis实例运用(基础篇),但是依旧遗留了一个问题,就是如果消费者消费的速度跟不上生产者,依旧会浪费我们大量的时间去等待,这时候我们就可以考虑使用多进程 ...
- 生产消费者模式与python+redis实例运用(基础篇)
根据这个图,我们举个简单的例子:假如你去某个餐厅吃饭,点了很多菜,厨师要一个一个菜的做,一个厨师不可能同时做出所有你点的菜,于是你有两个选择:第一个,厨师把所有菜都上齐了,你才开始吃:还有一个选择,做 ...
- 一台机器上搭建多个redis实例的配置文件修改部分
1.单个redis服务搭建请参考:redis服务搭建 2.一台Redis服务器,分成多个节点,每个节点分配一个端口(6380,6381…),默认端口是6379. 每个节点对应一个Redis配置文件,如 ...
随机推荐
- C#委托
关于什么是委托,委托如何使用,我在这里就不说了. 需要说的: 委托是函数指针链 委托的 BeginInvoke 委托如果出现异常,会如何 如果不知道函数指针,可以继续往下看,我来告诉大家,为何需要委托 ...
- 解决Nginx+Tomcat时ContextPath不同的问题
1 问题描述 项目前端模板使用Thymeleaf,在对各种URL进行格式化输出时,都使用@{uri}代码.它会自动读取项目部署的虚拟路径,添加到URI的前端输出. 真实测试和生产环境中, ...
- Mongodb常用的性能监控命令
1.显示服务器状态:db.serverStatus() 2.mongodb可以通过profile来监控数据,进行优化. 查看当前是否开启profile功能:db.getProfilingLe ...
- 兼容性问题--HTML+CSS
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px Consolas; color: #a5b2b9 } span.Apple-tab-span ...
- [Bayesian] “我是bayesian我怕谁”系列 - Naive Bayes+prior
先明确一些潜规则: 机器学习是个collection or set of models,一切实践性强的模型都会被归纳到这个领域,没有严格的定义,’有用‘可能就是唯一的共性. 机器学习大概分为三个领域: ...
- 不借助vue-cli,自行构建一个vue项目
前言: 对于刚刚接触vue的同学来说,直接用官方的构建工具vue-cli来生成一个项目结构会存在一些疑惑,比如: .vue组件 为什么可以写成三段式(tempalte.script.style)? ...
- angular1.x + ES6开发风格记录
angular1.x和ES6开发风格 一.Module ES6有自己的模块机制,所以我们要通过使用ES6的模块机制来淡化ng的框架,使得各业务逻辑层的看不出框架的痕迹,具体的做法是: 把各功能模块的具 ...
- 前后端分离跨服务器文件上传-Java SpringMVC版
近来工作上不上特别忙,加上对后台java了解一点,所以就抽时间,写了一个java版本的前后端分离的跨服务器文件上传功能,包括前后端代码. 一.Tomcat服务器部分 1.Tomcat服务器 单独复制一 ...
- Leetcode题解(十九)
54.Spiral Matrix 题目: 题目意思很简单,就是螺旋式访问矩阵元素.也没有比较经典的算法可以解决此题,只需要模拟一下这个过程即可. 代码如下: class Solution { publ ...
- Cable master
Problem Description Inhabitants of the Wonderland have decided to hold a regional programming contes ...