专栏首页卡二条的技术圈Redis实现列表数据查询设计

Redis实现列表数据查询设计

文章简介

本文总结个人在使用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
[1, 2, 4, 5, 6]
// 根据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', 6379, 1);
        $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去执行上面的逻辑。

文章分享自微信公众号:
卡二条的技术圈

本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!

作者:kert
原始发表时间:2021-02-27
如有侵权,请联系 cloudcommunity@tencent.com 删除。
登录 后参与评论
0 条评论

相关文章

  • 《Redis设计与实现》读书笔记(三十六) ——Redis 慢查询日志实现

    《Redis设计与实现》读书笔记(三十六) ——Redis 慢查询日志实现 (原创内容,转载请注明来源,谢谢) 一、基本功能 redis的慢查询日志,用于记录执...

    用户1327360
  • 《Redis设计与实现》读书笔记(三十七) ——Redis 慢查询日志实现

    《Redis设计与实现》读书笔记(三十七) ——Redis 慢查询日志实现 (原创内容,转载请注明来源,谢谢) 一、基本功能 通过monitor命令,redis...

    用户1327360
  • 《Redis设计与实现》读书笔记(六) ——Redis中的压缩列表

    《Redis设计与实现》读书笔记(六) ——Redis中的压缩列表 (原创内容,转载请注明来源,谢谢) 一、概述 压缩列表(ziplist)是列表键(list)...

    用户1327360
  • 《Redis设计与实现》读书笔记(八) ——Redis列表对象和哈希对象实现原理

    《Redis设计与实现》读书笔记(八) ——Redis列表对象和哈希对象实现原理 (原创内容,转载请注明来源,谢谢) 一、列表对象 列表对象的编码可以是zipl...

    用户1327360
  • Redis剖析——Redis列表实现原理之ZipList

    列表类型可以存储一组按插入顺序排序的字符串,它非常灵活,支持在两端插入、弹出数据,可以充当栈和队列的角色。

    binecy
  • Redis源码剖析——Redis列表实现原理之QuickList

    在上一篇文章《Redis列表实现原理之ziplist结构》,我们分析了ziplist结构如何使用一块完整的内存存储列表数据。

    binecy
  • 《Redis设计与实现》笔记1 | Redis单机数据库的实现

    创建键值对时包含 键对象 和 值对象 ,键对象总是一个字符串对象,值对象则有五种常用对象:字符串对象、列表对象、哈希对象、集合对象、有序集合对象。查看对象类型 ...

    素履coder
  • Redis 设计 --- 高效数据结构实现剖析

    即使有链表来处理键冲突,但是当节点数量远远大于 size 时,如果不扩充哈希表规模,请自行想象。这也是 rehash 的存在意义,笔者认为这也是 redis 扩...

    Arbiter
  • 基于Redis实现范围查询的IP库缓存设计方案

    我先说下结果。我现在还不敢放线上去测,这是本地测的数据,我4g内存的电脑本地开redis,一次都没写完过全部数据,都是写一半后不是redis挂就是测试程序挂。可...

    Bug开发工程师
  • 基于Redis实现范围查询的IP库缓存设计方案

    我先说下结果。我现在还不敢放线上去测,这是本地测的数据,我4g内存的电脑本地开redis,一次都没写完过全部数据,都是写一半后不是redis挂就是测试程序挂。可...

    Java艺术
  • Redis数据结构-压缩列表

    Redis 为了节约内存空间使用,zset 和 hash 容器对象在元素个数较少的时候,采用压缩列表 (ziplist) 进行存储。

    程序员酷森
  • Redis命令:scan实现模糊查询

    从Redis v2.8开始,SCAN命令已经可用,它允许使用游标从keyspace中检索键。 对比KEYS命令,虽然SCAN无法一次性返回所有匹配结果,但是却规...

    用户1205080
  • SaaS平台:数据列表设计

    本文采用的分析方式是通过归纳、抽象的方法,得到SaaS系统的常见的列表设计方式,并基于抽象得到的模型进行适当的扩展,提供关于SaaS平台的列表设计创新解决方案。

    物流IT圈
  • 《Redis设计与实现》笔记2 | Redis多机数据库的实现

    通过slaveof命令可以实现主从辅助,被复制的服务器叫主服务器,执行复制的服务器叫从服务器,例如

    素履coder
  • Redis 设计与实现: redisObject 数据结构,以及 Redis 的数据类型

    redisObject 是 Redis 类型系统的核心, 数据库中的每个键、值,以及 Redis 本身处理的参数, 都表示为这种数据类型。

    一个会写诗的程序员
  • 《redis设计与实现》2-数据库实现篇

    上一篇文章介绍了redis基本的数据结构和对象《redis设计与实现》1-数据结构与对象篇

    kinnylee
  • 《redis 设计与实现》--总结

    Redis自己构建了简单动态字符串(Simple Dynamic String,SDS)来作为默认的字符串表示。 SDS的构造如下:

    小二三不乌
  • 《redis 设计与实现》--总结

    Redis自己构建了简单动态字符串(Simple Dynamic String,SDS)来作为默认的字符串表示。 SDS的构造如下:

    小二三不乌
  • 探索Redis设计与实现2:Redis内部数据结构详解——dict

    本文转自http://zhangtielei.com/posts/blog-redis-dict.html

    Java技术江湖

扫码关注腾讯云开发者

领取腾讯云代金券