Redis实现列表数据查询设计
卡二条的技术圈
共 10628字,需浏览 22分钟
·
2021-03-01 04:46
文章简介
本文总结个人在使用Redis存储列表数据业务场景下的一些思路。平常在使用数据查询时,我们一般会将查询出来的数据使用json_encode()序列化一下,然后根据数据ID存储到Redis中。这样针对列表类的数据,或许就不是很好的实现了(因为涉及到分页计算)。本文使用String和zset类型实现这样的功能。
数据存储结构
上图为zset缓存数据ID,和String缓存实际信息的一个映射关系。
zset中的分数和值都是数据的ID,是因为数据的ID是唯一的,zset中的值和分数也是唯一的。正好符合这种关系。
String存储实体信息。缓存key则以数据ID作为键名,值为序列化后的数据信息。
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);
}
}
问题总结
列表参数化查询如何处理?
列表数据一般都是有传递用户查询参数,这时候我们可以实现根据条件去数据库筛选出对应的数据ID,并且只查询ID即可,然后根据ID去执行上面的逻辑。
推荐阅读
评论