[redis]redis实现分页的方法
每个主题下的用户的评论组装好写入Redis中,每个主题会有一个topicId,每一条评论会和topicId关联起来,大致的数据模型如下:
{ topicId: 'xxxxxxxx', comments: [ { username: 'niuniu', createDate: 1447747334791, content: '在Redis中分页', commentId: 'xxxxxxx', reply: [ { content: 'yyyyyy' username: 'niuniu' }, ... ] }, ... ]}
将评论数据从MySQL查询出来组装好存到Redis后,以后每次就可以从Redis获取组装好的评论数据,从上面的数据模型可以看出数据都是key-value型数据,无疑要采用hash进行存储,但是每次拿取评论数据时需要分页而且还要按createDate字段进行排序,hash肯定是不能做到分页和排序的。
那么,就挨个看一下Redis所支持的数据类型:
1、String: 主要用于存储字符串,显然不支持分页和排序。
2、Hash: 主要用于存储key-value型数据,评论模型中全是key-value型数据,所以在这里Hash无疑会用到。
3、List: 主要用于存储一个列表,列表中的每一个元素按元素的插入时的顺序进行保存,如果我们将评论模型按createDate排好序后再插入List中,似乎就能做到排序了,而且再利用List中的LRANGE key start stop指令还能做到分页。嗯,到这里List似乎满足了我们分页和排序的要求,但是评论还会被删除,就需要更新Redis中的数据,如果每次删除评论后都将Redis中的数据全部重新写入一次,显然不够优雅,效率也会大打折扣,如果能删除指定的数据无疑会更好,而List中涉及到删除数据的就只有LPOP和RPOP这两条指令,但LPOP和RPOP只能删除列表头和列表尾的数据,不能删除指定位置的数据,(备注:其实还有 LREM命令可以做到删除,但是非常不方便),而且当存在接口高并发访问时,这个list可能会无限延长,且里面的数据会存在很多重复,这就会影响到正常的业务,所以List也不太适合。
4、Set: 主要存储无序集合,无序!排除。
5、SortedSet: 主要存储有序集合,SortedSet的添加元素指令ZADD key score member [[score,member]…]会给每个添加的元素member绑定一个用于排序的值score,SortedSet就会根据score值的大小对元素进行排序,在这里就可以将createDate当作score用于排序,SortedSet中的指令ZREVRANGE key start stop又可以返回指定区间内的成员,可以用来做分页,SortedSet的指令ZREM key member可以根据key移除指定的成员,能满足删评论的要求,所以,SortedSet在这里是最适合的(时间复杂度O(log(N)))。
所以,需要用到的数据类型有SortSet和Hash,SortSet用于做分页排序,Hash用于存储具体的键值对数据。SortSet结构中将每个主题的topicId作为set的key,将与该主题关联的评论的createDate和commentId分别作为set的score和member,commentId的顺序就根据createDate的大小进行排列。
当需要查询某个主题某一页的评论时,就可主题的topicId通过指令zrevrange topicId (page-1)×10 (page-1)×10+perPage这样就能找出某个主题下某一页的按时间排好顺序的所有评论的commintId。page为查询第几页的页码,perPage为每页显示的条数。
当找到所有评论的commentId后,就可以把这些commentId作为key去Hash结构中去查询该条评论对应的内容。
这样就利用SortSet和Hash两种结构在Redis中达到了分页和排序的目的。
当然,也可以直接只使用SrotedSet类型,而不使用Hash类型,直接将评论存放在member中。
但为什么要将评论和排序放到不同的类型里?其中的好处是,可以对评论设置不同的排序类型,比如按时间的正反序,点赞的正反序,查看次数的正反序等。而这样只需要维护不同的SrotedSet排序,不需要维护多套评论的内容了。
下面是示例:
需要引用下面两个jar包
采用的jedis-2.8.1.jar
因为JedisPool引用了第三方类库,需要再加入 commons-pool2-2.4.2.jar
代码如下:
public static void main(String[] args)
{
for (int i = 1; i <= 100; i += 1) {
// 初始化CommentId索引 SortSet
RedisClient.zadd("topicId", i, "commentId" + i);
// 初始化Comment数据 Hash
RedisClient.hset("Comment_Key", "commentId" + i, "comment content "+ i +" .......");
}
// 倒序取 从0条开始取 5条 Id 数据
Set<String> sets = RedisClient.zrevrangebyscore("topicId", "100", "1", 0, 10);
String[] items = new String[]{};
System.out.println(sets.toString());
// 根据id取comment数据
List<String> list = RedisClient.hmget("Comment_Key", sets.toArray(items));
for (String str : list) {
System.out.println(str);
} }
其中的RedisClient类的代码如下:
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set; import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCommands;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig; /**
* Redis 客户端
*/
public class RedisClient { private static JedisPool jedisPool; static { JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(123);
config.setMaxTotal(1024);
config.setMaxIdle(10);
config.setMaxWaitMillis(1000);
config.setTestOnBorrow(true);
config.setTestOnReturn(true); String ip = "192.168.80.128";
int port = 6379;
int timeOut = 2000;
String password="jdd.com"; jedisPool = new JedisPool(config,ip,port,timeOut,password); } public static String set(String key, String value) {
Jedis jedis = jedisPool.getResource();
String result = jedis.set(key, value);
jedis.close();
return result;
} public static String get(String key) {
Jedis jedis = jedisPool.getResource();
String result = jedis.get(key);
jedis.close();
return result;
} public static Long hset(String key, String item, String value) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.hset(key, item, value);
jedis.close();
return result;
} public static String hget(String key, String item) {
Jedis jedis = jedisPool.getResource();
String result = jedis.hget(key, item);
jedis.close();
return result;
} /**
* Redis Hmget 命令用于返回哈希表中,一个或多个给定字段的值。
* 如果指定的字段不存在于哈希表,那么返回一个 nil 值。
*
* @param key
* @param item
* @return 一个包含多个给定字段关联值的表,表值的排列顺序和指定字段的请求顺序一样。
*/
public static List<String> hmget(String key, String... item) {
Jedis jedis = jedisPool.getResource();
List<String> result = jedis.hmget(key, item);
jedis.close();
return result;
} public static Long incr(String key) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.incr(key);
jedis.close();
return result;
} public static Long decr(String key) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.decr(key);
jedis.close();
return result;
} public static Long expire(String key, int second) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.expire(key, second);
jedis.close();
return result;
} public static Long ttl(String key) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.ttl(key);
jedis.close();
return result;
} public static Long hdel(String key, String item) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.hdel(key, item);
jedis.close();
return result;
} public static Long del(String key) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.del(key);
jedis.close();
return result;
} public static Long rpush(String key, String... strings) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.rpush(key, strings);
jedis.close();
return result;
} /**
* Redis Lrange 返回列表中指定区间内的元素,区间以偏移量 START 和 END 指定。 其中 0 表示列表的第一个元素, 1 表示列表的第二个元素,以此类推。
* 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
*
* @param string
* @param start
* @param end
* @return
*/
public static List<String> lrange(String key, int start, int end) {
Jedis jedis = jedisPool.getResource();
List<String> result = jedis.lrange(key, start, end);
jedis.close();
return result;
} /**
* 从列表中从头部开始移除count个匹配的值。如果count为零,所有匹配的元素都被删除。如果count是负数,内容从尾部开始删除。
*
* @param string
* @param string2
* @param i
*/
public static Long lrem(String key, Long count, String value) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.lrem(key, count, value);
jedis.close();
return result;
} /**
* Redis Zadd 命令用于将一个或多个成员元素及其分数值加入到有序集当中。
* 如果某个成员已经是有序集的成员,那么更新这个成员的分数值,并通过重新插入这个成员元素,来保证该成员在正确的位置上。
* 分数值可以是整数值或双精度浮点数。
* 如果有序集合 key 不存在,则创建一个空的有序集并执行 ZADD 操作。
* 当 key 存在但不是有序集类型时,返回一个错误。
*
* @param string
* @param i
* @param string2
* @return 被成功添加的新成员的数量,不包括那些被更新的、已经存在的成员。
*/
public static Long zadd(String key, double score, String member) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.zadd(key, score, member);
jedis.close();
return result;
} /**
* Redis Zrevrangebyscore 返回有序集中指定分数区间内的所有的成员。有序集成员按分数值递减(从大到小)的次序排列。
* 具有相同分数值的成员按字典序的逆序(reverse lexicographical order )排列。
* 除了成员按分数值递减的次序排列这一点外, ZREVRANGEBYSCORE 命令的其他方面和 ZRANGEBYSCORE 命令一样。
*
* @param key
* @param max
* @param min
* @param offset
* @param count
* @return 指定区间内,带有分数值(可选)的有序集成员的列表。
*/
public static Set<String> zrevrangebyscore(String key, String max, String min, int offset, int count) {
Jedis jedis = jedisPool.getResource();
Set<String> result = jedis.zrevrangeByScore(key, max, min, offset, count);
jedis.close();
return result;
}
}
[redis]redis实现分页的方法的更多相关文章
- 基于redis的处理session的方法
一个基于redis的处理session的方法,如下. <?php class Session_custom { private $redis; // redis实例 private $prefi ...
- .NET中Redis安装部署及使用方法简介
一Redis服务端以服务方式运行 修改端口压缩文件中配置的是6488 修改密码 修改库的数量 工具配置安装后如下图 二Redis服务端以控制台方式运行 第一步配置本地服务 第二部安装和配置客户端 三C ...
- ServiceStack.Redis遇到的问题:ServiceStack.Redis.Generic.RedisTypedClient`1”的方法“get_Db”没有实现。
问题: ServiceStack.Redis.Generic.RedisTypedClient`1”的方法“get_Db”没有实现. 解决方案: step 1::引用的三个 包版本保持一致 Servi ...
- 查看redis占用内存大小的方法
查看redis占用内存大小的方法 <pre>redis-cli auth 密码info</pre><pre># Memory used_memory:1349009 ...
- phpredis 报错 “Function Redis::setTimeout() is deprecated” 解决方法
项目在本地开发过程中抛出异常: Function Redis::setTimeout() is deprecated 找到出错代码: <?php use Illuminate\Support\F ...
- redis 清除minerd进程的方法
redis 清除minerd进程的方法 1 修改redis配置文件 //禁止高危命令rename-command FLUSHALL ""rename-command CONFIG ...
- 下载文件时-修改文件名字 Redis在Windows中安装方法 SVN安装和使用(简单版) WinForm-SQL查询避免UI卡死 Asp.Net MVC Https设置
下载文件时-修改文件名字 1后台代码 /// <summary> /// 文件下载2 /// </summary> /// <param name="Fil ...
- redis 五种常见攻击方法
如果需要大佬写好的脚本,可以直接去github上面搜 参考文章:https://www.cnblogs.com/wineme/articles/11731612.html https://www ...
- python redis自带门神 lock 方法
redis 支持的数据结构比较丰富,自制一个锁也很方便,所以极少提到其原生锁的方法.但是在单机版redis的使用时,自带锁的使用还是非常方便的.自己有车还打啥滴滴顺风车是吧,本篇主要介绍redis-p ...
- redis.Redis与redis.StrictRedis区别
redis-py提供两个类Redis和StrictRedis用于实现Redis的命令,StrictRedis用于实现大部分官方的命令,并使用官方的语法和命令(比如,SET命令对应与StrictRedi ...
随机推荐
- JSON parse error: syntax error, expect {, actual error, pos 0, fastjson-version 1.2.58; nested exception is com.alibaba.fastjson.JSONExcetion: syntax error, except {, actual error, pos ...
这个报错信息告诉你,你提交的参数需要是json类型.所以,POST请求携带的数据需要序列化一下json.dumps(data).
- pxc 5.6 忘记 root 密码
pxc 5.6 忘记密码处理 只说思路: mysql.user 是 myisam 引擎的,pxc 只支持 innodb 引擎.其他存储引擎的更改不复制.然而,DDL(Data Definition L ...
- Jquery实现类似百度的搜索框
最近工作中需要做一个搜索框,类似百度的搜索框,需要达到两个功能: 1.输入关键字,展示匹配的下拉列表 2.选择匹配的项后查出相关内容 一般电商网站中也经常用到该搜索条,首先分析功能实现,输入关键字马上 ...
- java-接口—策略模式
策略模式,就是不同类继承相同的接口,实现不同的策略.
- 【2019中国大学生程序设计竞赛-女生专场】C - Function
原题 韦神提供的思路orz 首先一个显然的性质,所有的c可以提出来,方程变成ax^2+bx的形式 因为x的值是离散的,而m的值又不大 所以一开始让x都为1(注意!x是正整数),然后每次挑一个x让他加一 ...
- maven的配置和eclipse maven插件安装
1.下载maven:http://maven.apache.org/download.cgi 2. 配置环境变量: 3. 修改maven文件夹下bin/conf/settings.xml:maven仓 ...
- python: 错误处理try详解 ,traceback调用栈, 调试(logging)
摘录:https://www.liaoxuefeng.com/wiki/1016959663602400/1017598873256736 错误处理 调试 错误处理 高级语言都会使用内置的一套try. ...
- @Mapper和@Repository
参考地址 https://www.cnblogs.com/jtfr/p/10962205.html 相同点 两者都是作用于dao上 不同点 @Repository需要在Spring中配置扫描地址,然后 ...
- 洛谷P3810-陌上开花(三维偏序, CDQ, 树状数组)
链接: https://www.luogu.org/problem/P3810#submit 题意: 一个元素三个属性, x, y, z, 给定求f(b) = {ax <= bx, ay < ...
- [旧版] CASthesis 模板编译的问题
写在前面的话:国科大最新版的模板在这里(https://github.com/mohuangrui/ucasthesis),利用它来写博后出站报告的相关介绍在这里: 本篇博文是针对另一个模板进行介绍的 ...