Redis缓存列表数据设计

A梦多啦A 发表于 2021/03/09 23:26:13 2021/03/09
【摘要】 使用Redis缓存列表数据方案设计。

文章简介

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

数据存储结构

Snipaste_2021-02-27_13-52-33
上图为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;

后台数据维护

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

代码演示

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去执行上面的逻辑。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区),文章链接,文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:cloudbbs@huaweicloud.com进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。