ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Redisson RLexSortedSet 使用指南:基于 Valkey/Redis 的分布式字典序字符串集合

Redisson RLexSortedSet 使用指南:基于 Valkey/Redis 的分布式字典序字符串集合 Redisson RLexSortedSet 使用指南基于 Valkey/Redis 的分布式字典序字符串集合【免费下载链接】redissonRedisson: Valkey Redis Java Client and Real-Time Data Platform. Sync/Async/RxJava/Reactive API. Over 50 Valkey and Redis based Java objects and services: Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Bloom filter, Spring, Tomcat, Scheduler, JCache API, Hibernate, RPC, local cache..项目地址: https://gitcode.com/GitHub_Trending/re/redisson导读本文围绕 Redisson 提供的RLexSortedSet分布式对象展开它是一款只存储String元素、并自动按字典序lexicographical order排序的 Java 集合实现了java.util.SetString与RSortedSetString接口。读完本文你将掌握如何通过同步、异步、Reactive 与 RxJava3 四种编程模型操作该集合如何利用其内置的范围查询、分页、排名统计与批量删除能力构建自动补全、字母索引、词典式检索等应用并理解其在底层如何借助 Valkey/Redis 的 ZSet 词法命令实现高效读写。概述什么是 RLexSortedSetRLexSortedSet是基于 Valkey 或 Redis 的分布式有序集合仅存储String类型元素并实现了java.util.SetString接口。与普通 Set 不同它会在元素添加时自动维护字典序字母表序因此非常适合需要有序字符串数据的场景例如自动补全autocomplete系统字母顺序索引词典式查找dictionary-style lookups该对象是线程安全的单个集合的元素数量上限为4 294 967 295即 2³²−1个。Valkey/Redis 通过序列化状态判断值是否唯一而不是依赖 Java 的hashCode()/equals()方法。由于它是RSortedSetString因此first()、last()以及有序迭代开箱即用但继承自java.util.SortedSet的范围视图subSet、headSet、tailSet不被支持——需要改用下文介绍的range系列方法。从源码结构看该对象由 RedissonLexSortedSet 实现它继承自RedissonScoredSortedSetString并实现了 RLexSortedSet 接口接口本身又继承RLexSortedSetAsync、RSortedSetString与RExpirable因此集合天然具备过期能力如expire()、delete()等。字典序排序原理RLexSortedSet按字符串的逐字节比较结果维护所有元素的字典序。元素在添加时即自动完成排序无需额外配置。排序遵循标准词典规则例如 apple 排在 banana 之前a1 排在 a2 之前。底层实现上RedissonLexSortedSet.addAsync 通过ZADD命令以固定 score 值0写入元素Valkey/Redis 的 ZSet 在 score 相同时会按成员字符串的字典序排列从而天然获得词法排序能力。这也是该对象容量受限于 2³²−1 的原因——ZSet 在 score 相同的情况下只允许该数量的元素。快速上手四种编程模型RLexSortedSet支持 Redisson 的四种编程模型同步Sync、异步Async、ReactiveProject Reactor与 RxJava3。首先通过RedissonClient获取集合对象RLexSortedSet set redisson.getLexSortedSet(myLexSet);获取客户端实例可参考 getting-started.md 与 configuration.md。同步 APIRLexSortedSet set redisson.getLexSortedSet(myLexSet); // 添加元素——自动按字典序排序 set.add(banana); set.add(apple); set.add(cherry); set.add(apricot); // 元素存储顺序为: apple, apricot, banana, cherry // 获取第一个字典序最小元素 String first set.first(); // 返回 apple // 获取最后一个字典序最大元素 String last set.last(); // 返回 cherry // 取出并移除第一个元素 String polledFirst set.pollFirst(); // 返回 apple // 取出并移除最后一个元素 String polledLast set.pollLast(); // 返回 cherry // 统计范围内元素数量 int count set.count(a, true, z, true); // 判断元素是否存在 boolean exists set.contains(banana); // 移除元素 boolean removed set.remove(banana);first()与last()在底层分别映射为ZRANGE key 0 0与ZRANGE key -1 -1见 RedissonScoredSortedSet.javapollFirst()/pollLast()则是在此基础上执行移除保证「取出即删」的原子语义。异步 APIRLexSortedSet set redisson.getLexSortedSet(myLexSet); // 异步添加元素 RFutureBoolean f1 set.addAsync(banana); RFutureBoolean f2 set.addAsync(apple); RFutureBoolean f3 set.addAsync(cherry); RFutureBoolean f4 set.addAsync(apricot); // 获取第一个字典序最小元素 RFutureString firstFuture set.firstAsync(); // 获取最后一个字典序最大元素 RFutureString lastFuture set.lastAsync(); // 取出并移除第一个元素 RFutureString polledFirstFuture set.pollFirstAsync(); // 取出并移除最后一个元素 RFutureString polledLastFuture set.pollLastAsync(); // 统计范围内元素数量 RFutureInteger countFuture set.countAsync(a, true, z, true); // 判断元素是否存在 RFutureBoolean existsFuture set.containsAsync(banana); // 移除元素 RFutureBoolean removedFuture set.removeAsync(banana);Reactive APIProject ReactorRedissonReactiveClient redisson redissonClient.reactive(); RLexSortedSetReactive set redisson.getLexSortedSet(myLexSet); // 响应式添加元素 MonoBoolean m1 set.add(banana); MonoBoolean m2 set.add(apple); MonoBoolean m3 set.add(cherry); MonoBoolean m4 set.add(apricot); // 获取第一个字典序最小元素 MonoString firstMono set.first(); // 获取最后一个字典序最大元素 MonoString lastMono set.last(); // 取出并移除第一个元素 MonoString polledFirstMono set.pollFirst(); // 取出并移除最后一个元素 MonoString polledLastMono set.pollLast(); // 统计范围内元素数量 MonoInteger countMono set.count(a, true, z, true); // 判断元素是否存在 MonoBoolean existsMono set.contains(banana); // 移除元素 MonoBoolean removedMono set.remove(banana);RxJava3 APIRedissonRxClient redisson redissonClient.rxJava(); RLexSortedSetRx set redisson.getLexSortedSet(myLexSet); // 使用 RxJava 添加元素 SingleBoolean s1 set.add(banana); SingleBoolean s2 set.add(apple); SingleBoolean s3 set.add(cherry); SingleBoolean s4 set.add(apricot); // 获取第一个字典序最小元素 MaybeString firstMaybe set.first(); // 获取最后一个字典序最大元素 MaybeString lastMaybe set.last(); // 取出并移除第一个元素 MaybeString polledFirstMaybe set.pollFirst(); // 取出并移除最后一个元素 MaybeString polledLastMaybe set.pollLast(); // 统计范围内元素数量 SingleInteger countSingle set.count(a, true, z, true); // 判断元素是否存在 SingleBoolean existsSingle set.contains(banana); // 移除元素 SingleBoolean removedSingle set.remove(banana);注意Reactive 与 RxJava3 中first()、last()、pollFirst()、pollLast()返回的是可能为空的Mono/Maybe因为集合为空时不存在对应元素而添加、删除、包含判断等布尔结果使用Mono/Single。范围查询Range OperationsRLexSortedSet提供了强大的范围查询能力可按字典序边界检索元素。范围操作同时支持包含inclusive与排除exclusive边界从而精确控制结果集合。这些操作直接复用 Valkey/Redis 原生的 ZSet 词法命令因此效率很高。从实现看RedissonLexSortedSet.java 中私有方法value()负责把「元素 是否包含」转换为 Redis 的边界语法包含时前缀[排除时前缀(无界下限用-无界上限用。例如range(apricot, true, blueberry, false)实际发送的命令是ZRANGEBYLEX myLexSet [apricot (blueberry对应命令定义见 RedisCommands.java。按值检索元素以下示例向集合中添加 6 个水果名称apple, apricot, banana, blueberry, cherry, cranberry。RLexSortedSet set redisson.getLexSortedSet(myLexSet); set.add(apple); set.add(apricot); set.add(banana); set.add(blueberry); set.add(cherry); set.add(cranberry); // 从头到指定值包含: 返回 apple, apricot, banana CollectionString head set.rangeHead(banana, true); // 从头到指定值排除: 返回 apple, apricot CollectionString headExclusive set.rangeHead(banana, false); // 从指定值到末尾包含: 返回 cherry, cranberry CollectionString tail set.rangeTail(cherry, true); // 从指定值到末尾排除: 返回 cranberry CollectionString tailExclusive set.rangeTail(cherry, false); // 两个值之间双包含: 返回 apricot, banana, blueberry CollectionString range set.range(apricot, true, blueberry, true); // 两个值之间起始包含、结束排除: 返回 apricot, banana CollectionString rangeMixed set.range(apricot, true, blueberry, false); // 逆字典序检索 CollectionString rangeReversed set.rangeReversed(apricot, true, cherry, true); CollectionString headReversed set.rangeHeadReversed(cherry, true); CollectionString tailReversed set.rangeTailReversed(banana, true);逆序系列在底层映射为ZREVRANGEBYLEX如 rangeTailReversedAsync直接返回降序结果无需在客户端二次排序。异步、Reactive、RxJava3 版本的对应方法为// Async RFutureCollectionString headFuture set.rangeHeadAsync(banana, true); RFutureCollectionString headExclusiveFuture set.rangeHeadAsync(banana, false); RFutureCollectionString tailFuture set.rangeTailAsync(cherry, true); RFutureCollectionString tailExclusiveFuture set.rangeTailAsync(cherry, false); RFutureCollectionString rangeFuture set.rangeAsync(apricot, true, blueberry, true); RFutureCollectionString rangeMixedFuture set.rangeAsync(apricot, true, blueberry, false); RFutureCollectionString rangeReversedFuture set.rangeReversedAsync(apricot, true, cherry, true); RFutureCollectionString headReversedFuture set.rangeHeadReversedAsync(cherry, true); RFutureCollectionString tailReversedFuture set.rangeTailReversedAsync(banana, true);// Reactive RedissonReactiveClient redisson redissonClient.reactive(); RLexSortedSetReactive set redisson.getLexSortedSet(myLexSet); set.add(apple).subscribe(); set.add(apricot).subscribe(); set.add(banana).subscribe(); set.add(blueberry).subscribe(); set.add(cherry).subscribe(); set.add(cranberry).subscribe(); MonoCollectionString headMono set.rangeHead(banana, true); MonoCollectionString headExclusiveMono set.rangeHead(banana, false); MonoCollectionString tailMono set.rangeTail(cherry, true); MonoCollectionString tailExclusiveMono set.rangeTail(cherry, false); MonoCollectionString rangeMono set.range(apricot, true, blueberry, true); MonoCollectionString rangeMixedMono set.range(apricot, true, blueberry, false); MonoCollectionString rangeReversedMono set.rangeReversed(apricot, true, cherry, true); MonoCollectionString headReversedMono set.rangeHeadReversed(cherry, true); MonoCollectionString tailReversedMono set.rangeTailReversed(banana, true);// RxJava3 RedissonRxClient redisson redissonClient.rxJava(); RLexSortedSetRx set redisson.getLexSortedSet(myLexSet); set.add(apple).subscribe(); set.add(apricot).subscribe(); set.add(banana).subscribe(); set.add(blueberry).subscribe(); set.add(cherry).subscribe(); set.add(cranberry).subscribe(); SingleCollectionString headSingle set.rangeHead(banana, true); SingleCollectionString headExclusiveSingle set.rangeHead(banana, false); SingleCollectionString tailSingle set.rangeTail(cherry, true); SingleCollectionString tailExclusiveSingle set.rangeTail(cherry, false); SingleCollectionString rangeSingle set.range(apricot, true, blueberry, true); SingleCollectionString rangeMixedSingle set.range(apricot, true, blueberry, false); SingleCollectionString rangeReversedSingle set.rangeReversed(apricot, true, cherry, true); SingleCollectionString headReversedSingle set.rangeHeadReversed(cherry, true); SingleCollectionString tailReversedSingle set.rangeTailReversed(banana, true);范围结果分页每个范围方法都带有接受offset与count的重载用于跳过与限制结果数量——这正是自动补全与分页浏览的基础。例如每次取 10 条匹配结果// Sync RLexSortedSet set redisson.getLexSortedSet(myLexSet); // 位于 ap 及其之后的 10 个元素——例如自动补全第 1 页 CollectionString page1 set.rangeTail(ap, true, 0, 10); // 接下来的 10 个 CollectionString page2 set.rangeTail(ap, true, 10, 10); // 在限定范围内分页 CollectionString firstTen set.range(a, true, z, true, 0, 10);// Async RFutureCollectionString page1 set.rangeTailAsync(ap, true, 0, 10); RFutureCollectionString page2 set.rangeTailAsync(ap, true, 10, 10); RFutureCollectionString firstTen set.rangeAsync(a, true, z, true, 0, 10);// Reactive RedissonReactiveClient redisson redissonClient.reactive(); RLexSortedSetReactive set redisson.getLexSortedSet(myLexSet); MonoCollectionString page1 set.rangeTail(ap, true, 0, 10); MonoCollectionString page2 set.rangeTail(ap, true, 10, 10); MonoCollectionString firstTen set.range(a, true, z, true, 0, 10);// RxJava3 RedissonRxClient redisson redissonClient.rxJava(); RLexSortedSetRx set redisson.getLexSortedSet(myLexSet); SingleCollectionString page1 set.rangeTail(ap, true, 0, 10); SingleCollectionString page2 set.rangeTail(ap, true, 10, 10); SingleCollectionString firstTen set.range(a, true, z, true, 0, 10);分页在底层通过追加LIMIT offset count参数实现见 rangeHeadAsync分页逻辑完全在服务端完成不会把全量数据拉到客户端。此外还有一个按位置索引而非按值选取的range(int startIndex, int endIndex)对应异步rangeAsync例如range(0, 9)返回前十个元素。它仅存在于同步与异步接口上内部委托给父类valueRange实现见 RedissonLexSortedSet.java。元素位置rank / revRankrank返回元素在字典序中的 0 起始位置revRank返回从末尾数起的位置当元素不存在时两者都返回空。这在展示某个词在索引中的位置时非常实用。// Sync RLexSortedSet set redisson.getLexSortedSet(myLexSet); Integer rank set.rank(banana); // 从起始算起的位置0 起始 Integer revRank set.revRank(banana); // 从末尾算起的位置// Async RFutureInteger rank set.rankAsync(banana); RFutureInteger revRank set.revRankAsync(banana);// Reactive RedissonReactiveClient redisson redissonClient.reactive(); RLexSortedSetReactive set redisson.getLexSortedSet(myLexSet); MonoInteger rank set.rank(banana); MonoInteger revRank set.revRank(banana);// RxJava3 RedissonRxClient redisson redissonClient.rxJava(); RLexSortedSetRx set redisson.getLexSortedSet(myLexSet); MaybeInteger rank set.rank(banana); MaybeInteger revRank set.revRank(banana);底层上rank/revRank由父类 RedissonScoredSortedSet 通过ZRANK/ZREVRANK命令实现命令定义见 RedisCommands.java因此元素不存在时返回null/空Mono/空Maybe。统计范围内元素数量以下示例向集合中添加 5 个元素apple, apricot, banana, blueberry, cherry。// Sync RLexSortedSet set redisson.getLexSortedSet(myLexSet); set.add(apple); set.add(apricot); set.add(banana); set.add(blueberry); set.add(cherry); // 从头到指定值包含 int headCount set.countHead(banana, true); // 返回 3 // 从头到指定值排除 int headCountExclusive set.countHead(banana, false); // 返回 2 // 从指定值到末尾包含 int tailCount set.countTail(banana, true); // 返回 3 // 从指定值到末尾排除 int tailCountExclusive set.countTail(banana, false); // 返回 2 // 两个值之间双包含 int rangeCount set.count(apricot, true, cherry, true); // 返回 4 // 两个值之间起始包含、结束排除 int rangeCountMixed set.count(apricot, true, cherry, false); // 返回 3// Async RFutureInteger headCountFuture set.countHeadAsync(banana, true); RFutureInteger headCountExclusiveFuture set.countHeadAsync(banana, false); RFutureInteger tailCountFuture set.countTailAsync(banana, true); RFutureInteger tailCountExclusiveFuture set.countTailAsync(banana, false); RFutureInteger rangeCountFuture set.countAsync(apricot, true, cherry, true); RFutureInteger rangeCountMixedFuture set.countAsync(apricot, true, cherry, false);// Reactive RedissonReactiveClient redisson redissonClient.reactive(); RLexSortedSetReactive set redisson.getLexSortedSet(myLexSet); MonoInteger headCountMono set.countHead(banana, true); MonoInteger headCountExclusiveMono set.countHead(banana, false); MonoInteger tailCountMono set.countTail(banana, true); MonoInteger tailCountExclusiveMono set.countTail(banana, false); MonoInteger rangeCountMono set.count(apricot, true, cherry, true); MonoInteger rangeCountMixedMono set.count(apricot, true, cherry, false);// RxJava3 RedissonRxClient redisson redissonClient.rxJava(); RLexSortedSetRx set redisson.getLexSortedSet(myLexSet); SingleInteger headCountSingle set.countHead(banana, true); SingleInteger headCountExclusiveSingle set.countHead(banana, false); SingleInteger tailCountSingle set.countTail(banana, true); SingleInteger tailCountExclusiveSingle set.countTail(banana, false); SingleInteger rangeCountSingle set.count(apricot, true, cherry, true); SingleInteger rangeCountMixedSingle set.count(apricot, true, cherry, false);count系列在底层映射为ZLEXCOUNT命令见 countHeadAsync 与 RedisCommands.java由服务端直接返回命中数量O(log N) 复杂度内即可完成统计无需拉取数据。按范围删除元素// Sync RLexSortedSet set redisson.getLexSortedSet(myLexSet); set.add(apple); set.add(apricot); set.add(banana); set.add(blueberry); set.add(cherry); set.add(cranberry); // 从头到指定值包含: 移除 apple, apricot int removedHead set.removeRangeHead(apricot, true); // 从头到指定值排除: 移除 banana 之前的元素 int removedHeadExclusive set.removeRangeHead(banana, false); // 从指定值到末尾包含: 移除 cherry, cranberry int removedTail set.removeRangeTail(cherry, true); // 从指定值到末尾排除: 移除 cherry 之后的元素 int removedTailExclusive set.removeRangeTail(cherry, false); // 两个值之间双包含 int removedRange set.removeRange(banana, true, cherry, true); // 两个值之间起始包含、结束排除 int removedRangeMixed set.removeRange(banana, true, cherry, false);// Async RFutureInteger removedHeadFuture set.removeRangeHeadAsync(apricot, true); RFutureInteger removedHeadExclusiveFuture set.removeRangeHeadAsync(banana, false); RFutureInteger removedTailFuture set.removeRangeTailAsync(cherry, true); RFutureInteger removedTailExclusiveFuture set.removeRangeTailAsync(cherry, false); RFutureInteger removedRangeFuture set.removeRangeAsync(banana, true, cherry, true); RFutureInteger removedRangeMixedFuture set.removeRangeAsync(banana, true, cherry, false);// Reactive RedissonReactiveClient redisson redissonClient.reactive(); RLexSortedSetReactive set redisson.getLexSortedSet(myLexSet); MonoInteger removedHeadMono set.removeRangeHead(apricot, true); MonoInteger removedHeadExclusiveMono set.removeRangeHead(banana, false); MonoInteger removedTailMono set.removeRangeTail(cherry, true); MonoInteger removedTailExclusiveMono set.removeRangeTail(cherry, false); MonoInteger removedRangeMono set.removeRange(banana, true, cherry, true); MonoInteger removedRangeMixedMono set.removeRange(banana, true, cherry, false);// RxJava3 RedissonRxClient redisson redissonClient.rxJava(); RLexSortedSetRx set redisson.getLexSortedSet(myLexSet); SingleInteger removedHeadSingle set.removeRangeHead(apricot, true); SingleInteger removedHeadExclusiveSingle set.removeRangeHead(banana, false); SingleInteger removedTailSingle set.removeRangeTail(cherry, true); SingleInteger removedTailExclusiveSingle set.removeRangeTail(cherry, false); SingleInteger removedRangeSingle set.removeRange(banana, true, cherry, true); SingleInteger removedRangeMixedSingle set.removeRange(banana, true, cherry, false);按范围删除在底层映射为ZREMRANGEBYLEX见 removeRangeHeadAsync 与 RedisCommands.java并返回实际删除的元素个数。监听器ListenersRedisson 允许为每个RLexSortedSet对象绑定监听器以接收集合变更通知。前提是必须在 Valkey/Redis 侧开启notify-keyspace-events配置。监听器类名事件描述Valkey/Redisnotify-keyspace-events值org.redisson.api.listener.TrackingListener读操作后元素被创建/删除/更新-org.redisson.api.listener.ScoredSortedSetAddListener元素被添加Ezorg.redisson.api.listener.ScoredSortedSetRemoveListener元素被移除Ezorg.redisson.api.ExpiredObjectListenerRLexSortedSet对象过期Exorg.redisson.api.DeletedObjectListenerRLexSortedSet对象被删除Eg监听器的注册与移除接口定义在 RLexSortedSet.java 中addListener(ObjectListener)。同步监听器示例RLexSortedSet set redisson.getLexSortedSet(myLexSet); // 元素添加监听器 int addListenerId set.addListener(new ScoredSortedSetAddListener() { Override public void onAdd(String name) { System.out.println(Element added to set: name); } }); // 元素移除监听器 int removeListenerId set.addListener(new ScoredSortedSetRemoveListener() { Override public void onRemove(String name) { System.out.println(Element removed from set: name); } }); // 集合过期监听器 int expireListenerId set.addListener(new ExpiredObjectListener() { Override public void onExpired(String name) { System.out.println(Set expired: name); } }); // 集合删除监听器 int deleteListenerId set.addListener(new DeletedObjectListener() { Override public void onDeleted(String name) { System.out.println(Set deleted: name); } }); // 读操作后跟踪变更的监听器 int trackingListenerId set.addListener(new TrackingListener() { Override public void onChange(String name) { System.out.println(Set changed after read: name); } }); // 不再需要时移除监听器 set.removeListener(addListenerId); set.removeListener(removeListenerId); set.removeListener(expireListenerId); set.removeListener(deleteListenerId); set.removeListener(trackingListenerId);异步、Reactive 与 RxJava3 监听器示例// Async RLexSortedSet set redisson.getLexSortedSet(myLexSet); RFutureInteger addListenerFuture set.addListenerAsync(new ScoredSortedSetAddListener() { Override public void onAdd(String name) { System.out.println(Element added to set: name); } }); RFutureInteger removeListenerFuture set.addListenerAsync(new ScoredSortedSetRemoveListener() { Override public void onRemove(String name) { System.out.println(Element removed from set: name); } }); RFutureInteger expireListenerFuture set.addListenerAsync(new ExpiredObjectListener() { Override public void onExpired(String name) { System.out.println(Set expired: name); } }); RFutureInteger deleteListenerFuture set.addListenerAsync(new DeletedObjectListener() { Override public void onDeleted(String name) { System.out.println(Set deleted: name); } }); // 移除监听器 addListenerFuture.thenAccept(listenerId - { set.removeListenerAsync(listenerId); });// Reactive RedissonReactiveClient redisson redissonClient.reactive(); RLexSortedSetReactive set redisson.getLexSortedSet(myLexSet); MonoInteger addListenerMono set.addListener(new ScoredSortedSetAddListener() { Override public void onAdd(String name) { System.out.println(Element added to set: name); } }); MonoInteger removeListenerMono set.addListener(new ScoredSortedSetRemoveListener() { Override public void onRemove(String name) { System.out.println(Element removed from set: name); } }); MonoInteger expireListenerMono set.addListener(new ExpiredObjectListener() { Override public void onExpired(String name) { System.out.println(Set expired: name); } }); MonoInteger deleteListenerMono set.addListener(new DeletedObjectListener() { Override public void onDeleted(String name) { System.out.println(Set deleted: name); } }); // 移除监听器 addListenerMono .flatMap(listenerId - set.removeListener(listenerId)) .subscribe();// RxJava3 RedissonRxClient redisson redissonClient.rxJava(); RLexSortedSetRx set redisson.getLexSortedSet(myLexSet); SingleInteger addListenerSingle set.addListener(new ScoredSortedSetAddListener() { Override public void onAdd(String name) { System.out.println(Element added to set: name); } }); SingleInteger removeListenerSingle set.addListener(new ScoredSortedSetRemoveListener() { Override public void onRemove(String name) { System.out.println(Element removed from set: name); } }); SingleInteger expireListenerSingle set.addListener(new ExpiredObjectListener() { Override public void onExpired(String name) { System.out.println(Set expired: name); } }); SingleInteger deleteListenerSingle set.addListener(new DeletedObjectListener() { Override public void onDeleted(String name) { System.out.println(Set deleted: name); } }); // 移除监听器 addListenerSingle .flatMapCompletable(listenerId - set.removeListener(listenerId)) .subscribe();测试用例 RedissonLexSortedSetTest.java 验证了监听器的实际生效测试通过NOTIFY_KEYSPACE_EVENTS, Ez参数开启键空间通知后向集合添加元素并断言监听器在 1 秒内被触发。源码视角命令映射一览下表汇总了本文涉及的RLexSortedSet操作与底层 Valkey/Redis 命令的对应关系均可在 RedissonLexSortedSet.java 与 RedisCommands.java 中验证API 方法Redis 命令说明add / addAllZADD固定 score 0字典序由 ZSet 天然维护first / lastZRANGE key 0 0 / key -1 -1取最小/最大元素rangeHead / rangeTail / rangeZRANGEBYLEX按词法边界取范围可带 LIMITrange*ReversedZREVRANGEBYLEX逆字典序范围count / countHead / countTailZLEXCOUNT服务端统计范围数量removeRange / removeRangeHead / removeRangeTailZREMRANGEBYLEX服务端批量删除并返回数量rank / revRankZRANK / ZREVRANK0 起始位置 / 从末尾起位置实用建议自动补全分页组合rangeTail(prefix, true, offset, count)即可实现前缀匹配 游标翻页所有计算都在服务端完成。测试 testLexRangeTail 展示了offset/count的实际效果。边界语义包含边界对应 Redis 的[前缀排除边界对应(前缀-与代表无界。需要精确控制结果时务必明确每个布尔参数。容量意识单集合最多 2³²−1 个元素超大字典场景应规划好分片可参考 contenteditable="false">【免费下载链接】redissonRedisson: Valkey Redis Java Client and Real-Time Data Platform. Sync/Async/RxJava/Reactive API. Over 50 Valkey and Redis based Java objects and services: Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Bloom filter, Spring, Tomcat, Scheduler, JCache API, Hibernate, RPC, local cache..项目地址: https://gitcode.com/GitHub_Trending/re/redisson创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表