有序集合和集合类似,只是说它是有序的,和无序集合的主要区别在于每一个元素除了值之外,它还会多一个分数。分数是一个浮点数,在 Java 中是使用双精度表示的,根据分数,Redis 就可以支持对分数从小到大或者从大到小的排序。

这里和无序集合一样,对于每一个元素都是唯一的,但是对于不同元素而言,它的分数可以一样。元素也是 String 数据类型,也是一种基于 hash 的存储结构。

集合是通过哈希表实现的,所以添加、删除、查找的复杂度都是 0(1)。集合中最大的成员数为 2 的 32 次方减 1(40 多亿个成员),有序集合的数据结构如图所示。

有序集合是依赖 key 标示它是属于哪个集合,依赖分数进行排序,所以值和分数是必须的,而实际上不仅可以对分数进行排序,在满足一定的条件下,也可以对值进行排序。

Redis基础命令

有序集合和无序集合的命令是接近的,只是在这些命令的基础上,会增加对于排序的操作,这些是我们在使用的时候需要注意的细节。

下面讲解这些常用的有序集合的部分命令。有些时候 Redis 借助数据区间的表示方法来表示包含或者不包含,比如在数学的区间表示中,[2,5] 表示包含 2,但是不包含 5 的区间。

Redis有序集合的部分命令

在对有序集合、下标、区间的表示方法进行操作的时候,需要十分小心命令,注意它是操作分数还是值,稍有不慎就会出现问题。

这里命令比较多,也有些命令比较难使用,在使用的时候,务必要小心,不过好在我们使用 zset 的频率并不是太高,下面是测试结果——有序集合命令展示。

spring-data-redis对有序集合的封装

在 Spring 中使用 Redis 的有序集合,需要注意的是 Spring 对 Redis 有序集合的元素的值和分数的范围(Range)和限制(Limit)进行了封装,在演示如何使用 Spring 操作有序集合前要进一步了解它的封装。

先介绍一个主要的接口——TypedTuple,它不是一个普通的接口,而一个内部接口,它是 org.springframework.data.redis.core.ZSetOperations 接口的内部接口,它定义了两个方法,代码如下所示。

public interface ZSetOperations<K,V>{......
public interface TypedTuple<V> extends Comparable<TypedTuple<V>< {V getValue();Double getScore();
}
......
}

这里的 getValue() 是获取值,而 getScore() 是获取分数,但是它只是一个接口,而不是一个实现类。spring-data-redis 提供了一个默认的实现类—— DefaultTypedTuple,同样它会实现 TypedTuple 接口,在默认的情况下 Spring 就会把带有分数的有序集合的值和分数封装到这个类中,这样就可以通过这个类对象读取对应的值和分数了。

Spring 不仅对有序集合元素封装,而且对范围也进行了封装,方便使用。它是使用接口 org.springframework.data.redis.connection.RedisZSetCommands 下的内部类 Range 进行封装的,它有一个静态的 range() 方法,使用它就可以生成一个 Range 对象了,只是要清楚 Range 对象的几个方法才行,为此我们来看看下面的伪代码。

//设置大于等于min
public Range gte(Object min)
//设置大于min
public Range gt(Object min)
//设置小于等于max
public Range lte(Object max)
//设置小于max
public Range lt(Object max)

这 4 个方法就是最常用的范围方法。下面讨论一下限制,它是接口 org.springframework.data.redis.connection.RedisZSetCommands 下的内部类,它是一个简单的 POJO,它存在两个属性,它们的 getter 和 setter 方法,如下面的代码所示。

// ......
public interface RedisZSetCommands {// ......
public class Limit {int offset;int count;
//setter和getter方法
}
//......
}

通过属性的名称很容易知道:offset 代表从第几个开始截取,而 count 代表限制返回的总数量。

通过 Spring 操作有序集合

我们讨论了 spring-data-redis 项目对有序集合的封装。在测试代码前,要把 RedisTemplate 的 keySerializer 和 valueSerializer 属性都修改为字符串序列化器 StringRedisSerializer,测试代码如下所示。

public static void testZset() {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");RedisTemplate redisTemplate = applicationContext.getBean(RedisTemplate.class);// Spring提供接口 TypedTuple操作有序集合Set<TypedTuple> set1 = new HashSet<TypedTuple>();Set<TypedTuple> set2 = new HashSet<TypedTuple>();int j = 9;for (int i = 1; i <= 9; i++) {j--;// 计算分数和值Double score1 = Double.valueOf(i);String value1 = "x" + i;Double score2 = Double.valueOf(j);String value2 = j % 2 == 1 ? "y" + j : "x" + j;// 使用 Spring 提供的默认 TypedTuple--DefaultTypedTupleTypedTuple typedTuple1 = new DefaultTypedTuple(value1, score1);set1.add(typedTuple1);TypedTuple typedTuple2 = new DefaultTypedTuple(value2, score2);set2.add(typedTuple2);}// 将元素插入有序集合zset1redisTemplate.opsForZSet().add("zset1", set1);redisTemplate.opsForZSet().add("zset2", set2);// 统计总数Long size = null;size = redisTemplate.opsForZSet().zCard("set1");// 计分数为score,那么下面的方法就是求 3<=score<=6的元素size = redisTemplate.opsForZSet().count("zset1", 3, 6);Set set = null;// 从下标一开始截取5个元素,但是不返回分数,每一个元索是Stringset = redisTemplate.opsForZSet().range("zset1", 1, 5);printSet(set);// 截取集合所有元素,并且对集合按分数排序,并返回分数,每一个元素是TypedTupleset = redisTemplate.opsForZSet().rangeWithScores("zset1", 0, -1);printTypedTuple(set);// 将zset1和zset2两个集合的交集放入集合inter_zsetsize = redisTemplate.opsForZSet().intersectAndStore("zset1", "zset2","inter_zset");// 区间Range range = Range.range();range.lt("x8");// 小于range.gt("x1"); // 大于set = redisTemplate.opsForZSet().rangeByLex("zset1", range);printSet(set);range.lte("x8"); // 小于等于range.gte("xl"); // 大于等于set = redisTemplate.opsForZSet().rangeByLex("zset1", range);printSet(set);// 限制返回个数Limit limit = Limit.limit();// 限制返回个数limit.count(4);// 限制从第五个开始截取limit.offset(5);// 求区间内的元素,并限制返回4条set = redisTemplate.opsForZSet().rangeByLex("zset1", range, limit);printSet(set);// 求排行,排名第1返回0,第2返回1Long rank = redisTemplate.opsForZSet().rank("zset1", "x4");System.err.println("rank = " + rank);// 删除元素,返回删除个数size = redisTemplate.opsForZSet().remove("zset1", "x5", "x6");System.err.println("delete = " + size);// 按照排行删除从0开始算起,这里将删除第排名第2和第3的元素size = redisTemplate.opsForZSet().removeRange("zset2", 1, 2);// 获取所有集合的元素和分数,以-1代表全部元素set = redisTemplate.opsForZSet().rangeWithScores("zset2", 0, -1);printTypedTuple(set);// 删除指定的元素size = redisTemplate.opsForZSet().remove("zset2", "y5", "y3");System.err.println(size);// 给集合中的一个元素的分数加上11Double dbl = redisTemplate.opsForZSet().incrementScore("zset1", "x1",11);redisTemplate.opsForZSet().removeRangeByScore("zset1", 1, 2);set = redisTemplate.opsForZSet().reverseRangeWithScores("zset2", 1, 10);printTypedTuple(set);
}/**
* 打印TypedTuple集合
* @param set
* -- Set<TypedTuple>
*/
public static void printTypedTuple(Set<TypedTuple> set) {if (set != null && set.isEmpty()) {return;}Iterator iterator = set.iterator();while (iterator.hasNext()) {TypedTuple val = (TypedTuple) iterator.next();System.err.print("{value = " + val.getValue() + ", score = "+ val.getScore() + "}\n");}
}/**
* 打印普通集合
* @param set普通集合
*/
public static void printSet(Set set) {if (set != null && set.isEmpty()) {return;}Iterator iterator = set.iterator();while (iterator .hasNext()) {Object val = iterator.next();System. out.print (val +"\t");}System.out.println();
}

上面的代码演示了大部分 Spring 对有序集合的操作,并给出了比较清晰的注释,大家认真思考之后就能熟悉如何通过 Spring 操作有序集合了。

Redis有序集合详解相关推荐

  1. Redis有序集合命令ZREMRANGEBYLEX详解与应用

    Redis有序集合命令ZREMRANGEBYLEX详解与应用 本文是我在Redis中文网翻译团队翻译redis命令的相关内容,也是取得翻译团队同意后在CSDN同步发表 redis.cn翻译团队 也欢迎 ...

  2. Redis有序集合命令ZRANGEBYLEX详解与应用

    Redis有序集合命令ZRANGEBYLEX详解与应用 1 简介 ZRANGEBYLEX 返回指定成员区间内的成员 此指令适用于分数相同的有序集合中 LEX结尾的指令是要求分数必须相同 2 语法 2. ...

  3. redis有序集合zset详解

    zset 概述 Redis有序集合zset与普通集合set非常相似,是一个没有重复元素的字符串集合. 不同之处是有序集合的每个成员都关联了一个评分(score),这个评分(score)被用来按照从最低 ...

  4. Redis AOF 持久化详解

    来自公众号:程序员历小冰 Redis 是一种内存数据库,将数据保存在内存中,读写效率要比传统的将数据保存在磁盘上的数据库要快很多.但是一旦进程退出,Redis 的数据就会丢失. 为了解决这个问题,Re ...

  5. 转-Redis AOF 持久化详解

    转自: https://juejin.cn/post/6844903902991630349 Redis AOF 持久化详解 Redis 是一种内存数据库,将数据保存在内存中,读写效率要比传统的将数据 ...

  6. 探索Redis设计与实现6:Redis内部数据结构详解——skiplist

    Redis内部数据结构详解(6)--skiplist  2016-10-05 本文是<Redis内部数据结构详解>系列的第六篇.在本文中,我们围绕一个Redis的内部数据结构--skipl ...

  7. Redis最全详解(一)——基础介绍

    Redis介绍 redis是基于内存可持久化的日志型.Key-Value数据库.redis安装在磁盘,但是数据存储在内存.非关系型数据库NoSql.开源免费,遵守BSD协议,不用关注版权问题. red ...

  8. Redis分布式锁详解

    Redis分布式锁详解 1. 分布式所概述 1.1 分布式锁 2. 缓存数据库Redis 2.1 redis简介 2.2 Springboot整合Redis两种方式 3. 实现验证 3.1 环境准备 ...

  9. 1.8 Collections类操作集合详解——排序,查找,复制

    Collections类操作集合详解 Collections 类是 Java 提供的一个操作 Set.List 和 Map 等集合的工具类. Collections 类提供了许多操作集合的静态方法,借 ...

最新文章

  1. 新手探索NLP(四)
  2. php-fpm 没有启动脚本,php-fpm服务启动脚本
  3. redis 和 数据库mysql之间的关系
  4. jquery获取html页面参数乱码,JS或Jquery获取浏览器URL的参数值 汉字值乱码 并转码...
  5. linux的sonar安装,Linux安装sonar
  6. mysql 复杂的sql_mysql 一个复杂的sql
  7. pandas 0.22导入错误
  8. Python 函数3000字使用总结
  9. 361766103.jpg
  10. MD(d)、MT(d)编译选项的区别
  11. Python学习路程-常用设计模式学习
  12. linux新建虚拟机到图形化界面
  13. bjui 公共的弹窗确认 取消 改变文字
  14. SpringBoot整合thymeleaf和Shiro项目绑定JS接口安全域名问题
  15. 我用 python 做了款可开淘宝店赚钱的工具
  16. lm做自相关做几阶_lm检验(lm检验怎么判断是几阶自相关)
  17. 135微信编辑html语言,135微信编辑器如何使用 135编辑器微信文章编辑教程
  18. Excel—PAPAYA电脑教室
  19. html chm 64,Win7 64位下的CHM
  20. 长春光机所计算机待遇,有谁知道长春光机所的工资待遇怎么样?硕士一年的收入大概是多少?...

热门文章

  1. hexo评论_【前端简历加分】hexo框架搭建个人博客站点,手把手教学
  2. php mvc教程 文档,PHP培训教程教你快速打造PHP MVC框架[PHP基础教程]
  3. mysql vs2008,vs2008 使用mysql
  4. Win11黑夜模式在哪开启 Win11黑夜模式怎么开启
  5. JAVA SSM框架+Redis 实现单点登录
  6. Java分布式篇6——RabbitMQ
  7. phpexcel.php实际应用,PHP操作excel的一个例子(原创)-PHP教程,PHP应用
  8. java会被rust替代吗_自从尝了 Rust,Java 突然不香了
  9. java spark wordcount_提交任务到spark(以wordcount为例)
  10. mfc 固定编辑框输入上限和下限_MFC中编辑框数字限制范围