Redis实现列表数据查询设计

卡二条的技术圈

共 10628字,需浏览 22分钟

 ·

2021-03-01 04:46

文章简介

本文总结个人在使用Redis存储列表数据业务场景下的一些思路。平常在使用数据查询时,我们一般会将查询出来的数据使用json_encode()序列化一下,然后根据数据ID存储到Redis中。这样针对列表类的数据,或许就不是很好的实现了(因为涉及到分页计算)。本文使用String和zset类型实现这样的功能。

数据存储结构

上图为zset缓存数据ID,和String缓存实际信息的一个映射关系。

  1. zset中的分数和值都是数据的ID,是因为数据的ID是唯一的,zset中的值和分数也是唯一的。正好符合这种关系。

  2. String存储实体信息。缓存key则以数据ID作为键名,值为序列化后的数据信息。

  3. zset中的值和String缓存中的key一一映射。

接口数据处理

接口获取数据一般就是传递一个页码(page)和一个分页大小(size)。我们先去zset中获取对应的ID。然后根据ID依次获取String中的数据。如何根据分页去读取zset中的ID呢?可以根据下面的公式:

// 开始位置
$start = ($page - 1) * $size;
// 结束位置
$end   = $start + $size;
// 获取ID
$idArray = $redis->zRange($key, $start, $end);
var_dump($idArray);
// output
[12456]
// 根据ID向Redis获取数据
$returnArray = [];
foreach ($idArray as $key => $value) {
    $returnArray[$key] = json_decode('cache:' . $value, true);
}

return $returnArray;

后台数据维护

用户端获取数据解决了,如果后台数据变更了,该如何处理呢?这里只要我们对后台的数据做了操作,去操作对应的缓存即可。整体思路如下:

代码演示

Redis连接

class RedisConnection
{
    public $redisConnection;

    public function __construct()
    
{
        $redis = new Redis();
        $redis->connect('192.168.2.102'63791);
        $redis->auth(6379);
        $this->redisConnection = $redis;
    }
}

MySQL连接

class DBConnection
{
    /**
     * 数据库类型
     * @var string
     */

    private $dbms = 'mysql';

    /**
     * 主机地址
     * @var string
     */

    private $host = 'mysql5';

    /**
     * 端口号
     * @var int
     */

    private $port = 3306;

    /**
     * 数据库名称
     * @var string
     */

    private $dbName = 'tools';

    /**
     * 用户名称
     * @var string
     */

    private $user = 'root';

    /**
     * 密码
     * @var string
     */

    private $pass = '123456';

    /**
     * 连接对象
     * @var PDO
     */

    public $dbConnection;

    public function __construct()
    
{
        try {
            $dbh                = new PDO("{$this->dbms}:host={$this->host};port:{$this->port};dbname={$this->dbName}",
                $this->user,
                $this->pass, [
                    PDO::ATTR_PERSISTENT => true
                ]);
            $this->dbConnection = $dbh;
        } catch (Exception $exception) {
            var_dump('MySQL连接异常:' . $exception->getMessage());
        }
    }
}

管理端

class Manage
{
    /**
     * Redis连接对象
     * @var Redis
     */

    private $redis;

    /**
     * MySQL连接对象
     * @var PDO
     */

    private $db;

    public function __construct()
    
{
        $this->db = (new DBConnection())->dbConnection;

        $this->redis = (new RedisConnection())->redisConnection;
    }

    /**
     * 数据增加
     * @return void
     */

    public function insert()
    
{
        // 添加的数据
        $data = [];
        // 1. 插入数据库
        $insertId = 0;
        // 2. 插入Redis
        // 2.1 插入string
        $this->redis->set('cache:' . $insertId, json_encode($data));
        // 2.2 插入zset
        $this->redis->zAdd('list', [], $insertId, $insertId);
    }

    /**
     * 数据更新
     * @return void
     */

    public function update()
    
{
        // 更新数据
        $data = [];
        // 1. 更新数据库
        $updatedId = 0;
        // 2. 更新Redis
        $this->redis->set('cache:' . $updatedId, json_encode($data));
    }

    /**
     * 数据删除
     * @return void
     */

    public function delete()
    
{
        // 1.删除数据id
        $deleteId = 0;
        // 2.删除Redis
        // 2.1删除string
        $this->redis->del('cache:' . $deleteId);
        // 2.2删除zset
        $this->redis->zDelete('list', $deleteId);
    }
}

接口端

class Api
{
    /**
     * Redis连接对象
     * @var Redis
     */

    private $redis;

    public function __construct()
    
{

        $this->redis = (new RedisConnection())->redisConnection;
    }

    /**
     * 获取列表
     * @return array
     */

    public function list()
    
{
        /**
         * 这里罗列普通的查询
         * 如果涉及到条件查询,可以先根据条件去MySQL中查询到主表的ID。在根据ID走这样的逻辑。
         */

        // 页码
        $page = 1;
        // 分页大小
        $size = 10;
        // 1.先根据分页获取zset中的id(分数)
        $start   = ($page - 1) * $size;
        $idArray = $this->redis->zRange('list', $start, $size + $start);
        // 2.根据获取到的id,去string中查找
        $returnArray = [];
        foreach ($idArray as $key => $value) {
            $returnArray[$key] = json_decode('cache:' . $value, true);
        }

        return $returnArray;
    }

    // 获取详情
    public function find()
    
{
        // 客户端请求的,数据id
        $id = 1;

        return json_decode($this->redis->get('cache:' . $id), true);
    }

}

问题总结

  1. 列表参数化查询如何处理?

列表数据一般都是有传递用户查询参数,这时候我们可以实现根据条件去数据库筛选出对应的数据ID,并且只查询ID即可,然后根据ID去执行上面的逻辑。

推荐阅读

  1. Redis缓存数据一致性解决方案分析

  2. Redis事务处理机制分析与总结

  3. Redis数据类型应用场景总结

  4. Redis的过期策略和内存淘汰策略最全总结与分析

  5. Redis持久化存储详解(一)



浏览 44
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报