学习笔记:使用 Spring RedisTemplate 通过 ZSET + HASH 实现分页
本文是本人在学习 Redis 时的整理笔记。学习过程中遇到需要将 MySQL 表中的数据缓存到 Redis 中,并且在展示时还要支持分页查询的场景。最初尝试单独使用 HASH 结构,但发现无法直接满足分页需求,通过查阅公开资料后,学习到可以结合 ZSET 与 HASH 两种结构一起使用来实现分页效果,因此在此做一份学习记录,方便自己日后复习。
一、思路整理
- 使用 ZSET 存储表中记录的
id,把id作为 ZSET 的 value,并利用 ZSET 的 score 字段进行排序; - 使用 HASH 结构存储完整的数据行,把
id作为 HASH 的 key; - 查询分页时,先通过
zRangeByScore在 ZSET 中按分数区间取出当前页的id列表,再依次到 HASH 中取出对应的数据即可。
二、代码练习
下面是我在学习过程中根据思路整理并练习的示例代码,仅用于自己练习理解 API,非线上项目代码:
/**
* 存放单个 hash 缓存
* @param key 键
* @param hkey hash 内部键
* @param value 值
*/
public static boolean hput(String key, String hkey, Object value) {
try {
redisTemplate.opsForHash().put(key, hkey, value);
log.debug("hput {} = {}", key + hkey, value);
return true;
} catch (Exception e) {
log.warn("hput {} = {}", key + hkey, value, e);
}
return false;
}
/**
* 分页存入数据
* @param key 业务 key 前缀
* @param hkey 数据在 hash 中的 key(可用 id)
* @param score 排序分数(可用时间戳或 id)
* @param value 具体数据
*/
public static boolean setPage(String key, String hkey, double score, String value) {
boolean result = false;
try {
redisTemplate.opsForZSet().add(key + ":page", hkey, score);
result = hput(key, hkey, value);
log.debug("setPage {}", key);
} catch (Exception e) {
log.warn("setPage {}", key, e);
}
return result;
}
/**
* 分页取出 hash 中对应 hkey 的集合
* @param key 业务 key 前缀
* @param offset 页码(从 1 开始)
* @param count 每页条数
*/
public static Set<String> getPage(String key, int offset, int count) {
Set<String> result = null;
try {
// 1 与 100000 是 score 的范围示例,实际使用时按需要调整
result = redisTemplate.opsForZSet()
.rangeByScore(key + ":page", 1, 100000, (offset - 1) * count, count);
log.debug("getPage {}", key);
} catch (Exception e) {
log.warn("getPage {}", key, e);
}
return result;
}
/**
* 获取当前 key 已缓存的数据总数(用于分页总数展示)
*/
public static Integer getSize(String key) {
Integer num = 0;
try {
Long size = redisTemplate.opsForZSet().zCard(key + ":page");
log.debug("getSize {}", key);
return size.intValue();
} catch (Exception e) {
log.warn("getSize {}", key, e);
}
return num;
}
三、我的一点心得
- ZSET 负责"顺序",HASH 负责"内容",两者分工非常清晰,也让我更好地理解了为什么 Redis 会提供这么多不同的数据结构;
score的选取要提前设计好,比如用创建时间戳或自增 id,否则后期无法稳定排序;- 练习过程中需要注意
(offset - 1) * count这种起始下标的写法,容易在边界条件出错; - 后续可以继续练习:加入更新缓存、删除缓存以及与 MySQL 数据一致性的处理方式。
本篇为个人学习整理笔记,用于自我复习。参考了公开的技术文章《spring 中 redisTemplate 实现 redis 分页》,并结合自己的理解重新整理注释。« 返回首页