写一些脚本的心得总结系列第4篇-------从数据库同步到redis

5.从数据库同步到redis的。

redis把数据放内存里,读取都非常方便,也提供了远超memcache的丰富数据结构。
下面我举2个例子,比如
1)把数据从数据库写入到redis:

<?php

$redis = MyRedis::getInstance();
$tables = ['users', 'games', 'tasks'];
foreach ($tables as $table)
{
    //echo '$i=' . $i,',$table=' . $table, "<br>";
    $sql = "select * from $table;";
    $datas = $mysql->select($sql);

    foreach ($datas as $data)
    {
        //往redis中写数据。
        if ($table == 'users')
        {
            $redis->hSet('mycloud_' . $table, $data['user_name'], json_encode($data));
        }

        else {
            $redis->hSet('mycloud_' . $table, $data['user_id'], json_encode($data));
        }

    }
}

Redis hash是一个string类型的field和value的映射表.它的添加、删除操作都是O(1)(平均)。
hash特别适合用于存储对象。相较于将对象的每个字段存成单个string类型。将一个对象存储在hash类型中会占用更少的内存,并且可以更方便的存取整个对象。省内存的原因是新建一个hash对象时开始是用zipmap(又称为small hash)来存储的。这个zipmap其实并不是hash table,但是zipmap相比正常的hash实现可以节省不少hash本身需要的一些元数据存储开销。尽管zipmap的添加,删除,查找都是O(n),但是由于一般对象的field数量都不太多。所以使用zipmap也是很快的,也就是说添加删除平均还是O(1)。如果field或者value的大小超出一定限制后,Redis会在内部自动将zipmap替换成正常的hash实现. 这个限制可以在配置文件中指定
  hash-max-zipmap-entries 64 #配置字段最多64个。
  hash-max-zipmap-value 512 #配置value最大为512字节。
  hset 设置hash field为指定值,如果key不存在,则先创建。Set结构会自动去重,且hset非常节省空间,所以整表数据写入redis可以用这个操作。
它的读取也很简单:
// 根据某用户名获取该用户记录信息
$redis = PHPRedis::getInstance(); //连接Redis数据库
$user = json_decode($redis->hget('mycloud_users', $userName), true);
return $user ? $user : array();

其中,json_decode第二个参数传true,将返回 array 而非 object 。

当然hSet的时候不一定非要用json_encode,也可以使用serialize。redis最重要的是要找到唯一key去对应存储数据。

2)登录日志同步到数据库
可以利用redis中的list操作来实现。

封装的redis 操作如下:

public function lPush($key, $data) {
    if ($this->conn) {
        return $this->_redis->lPush($key, json_encode($data));
    }
}

/**
 * 从队列右边取出一条记录
 * @param string $key 队列名称
 * @param bool $isBlock true-以阻塞方式读取;false-非阻塞方式读取
 */
public function rPop($key, $isBlock = true) {
    if ($this->conn) {
        if ($isBlock) {
            $result = $this->_redis->brPop($key);
        } else {
            $result = $this->_redis->rPop($key);
        }

        return json_decode($result, true);
    }

    return array();
}



任务队列一般适用于生产者和消费者之间通信的,那么在redis中很容易想到使用列表类型来实现任务队列,具体方法是创建一个任务队列,生产者主动lpush数据,而消费者去rpop数据,保持一个先进先出的循序。
但是这样存在一个问题,消费者需要主动去请求数据,周期性的请求会造成资源的浪费,因此,redis提供了一个brpop的命令来解决这个问题。
BRPOP key timeout
brpop命令接收两个参数,第一个参数key为键值,第二个参数timeout为超时时间。BRPOP命令取数据时候,如果暂时不存在数据,该命令会一直阻塞直到达到超时时间。如果timeout设置为0,那么就会无限等待下去。

这里默认是用了brPop方式,阻塞方式读取。

生产者相关调用代码:
<?php
// 登录相关代码....
$myRedis->lPush('users_login_log', $logData);


消费者的调用:

$listLog = $myRedis->rPop('usrs_login_log');
$row = json_decode($listLog, true);
// 后面再入库......

再聊就都是Redis实践的干货了,还是以后单开一篇博客来总结吧。

原文地址:https://www.cnblogs.com/freephp/p/5094658.html