引言

最近需要使用RedisTemplate操作Redis中的ZSet数据类型,本篇博客将记录一些常用方法,代码基于spring-boot-starter-data-redis 2.1.9.RELEASE版本。

ZSet数据结构

数据结构类似于Set结构,只是ZSet结构中,在set基础上加入了一个score字段,通过利用score进行相关的排序。
每个元素都会有一个分值(score),然后所有元素按照分值的大小进行排列,相当于是一个进行了排序的链表。

常用操作

下面通过增加人员(包含编号和年龄属性)集合,并通过人员的年龄进行排序。

1. 增加有序集合

/**
 * 增加有序集合
 *
 * @param key
 * @param value
 * @param seqNo
 * @return
 */
public Boolean addZset(String key, Object value, double seqNo) {
    try {
        return redisTemplate.opsForZSet().add(key, value, seqNo);
    } catch (Exception e) {
        log.error("[RedisUtils.addZset] [error]", e);
        return false;
    }
}
key和value存在新增失败,返回false;不存在新增成功,返回true。
示例代码:
// 初始化person集合
List<Person> personList = Arrays.asList(new Person(1287989870372388866L, 29), new Person(1287989874193399810L, 18), new Person(1287989878043770883L, 38), new Person(1287989866203250690L, 12), new Person(1287989956804411394L, 45));
for (int i = 0; i < personList.size(); i++) {
	// 新增,key为person,value为uuid唯一标识,score为年龄
    System.out.println(redisUtils.addZset("person", personList.get(i).getUuid(), personList.get(i).getAge()));
}

2. 获取集合数量

/**
 * 获取zset集合数量
 *
 * @param key
 * @return
 */
public Long countZset(String key) {
    try {
        return redisTemplate.opsForZSet().size(key);
    } catch (Exception e) {
        log.error("[RedisUtils.countZset] [error] [key is {}]", key, e);
        return 0L;
    }
}
key不存在,返回0;存在,返回集合的个数。
示例代码
// 查询key为person的集合个数
Long count = redisUtils.countZset("person");
System.out.println(count);

3. 获取指定范围内的集合

/**
 * 获取zset指定范围内的集合
 *
 * @param key
 * @param start
 * @param end
 * @return
 */
public Set<Object> rangeZset(String key, long start, long end) {
    try {
        return redisTemplate.opsForZSet().range(key, start, end);
    } catch (Exception e) {
        log.error("[RedisUtils.rangeZset] [error] [key is {},start is {},end is {}]", key, start, end, e);
        return null;
    }
}
key存在,返回集合的对应位置的元素,区间左开右闭。start从0开始,end传-1表示查询所有。
示例代码
// 查询所有
System.out.println(redisUtils.rangeZset("person", 0, -1));
// 结果
[1287989866203250690, 1287989874193399810, 1287989870372388866, 1287989878043770883, 1287989956804411394]
// 查询前3个
System.out.println(redisUtils.rangeZset("person", 0, 2));
// 结果
[1287989866203250690, 1287989874193399810, 1287989870372388866]

4. 移除集合内的元素

/**
 * 根据key和value移除指定元素
 *
 * @param key
 * @param value
 * @return
 */
public Long removeZset(String key, Object value) {
    return redisTemplate.opsForZSet().remove(key, value);
}
未查询到对应的key和value,返回0,否则返回1
示例代码
// 删除指定key和value对应的元素(存在的)
System.out.println(redisUtils.removeZset("person", 1287989874193399810L));
// 结果
1
// 删除指定key和value对应的元素(不存在的)
System.out.println(redisUtils.removeZset("111", 1287989874193399810L));
// 结果
0
// 查询删除后的所有元素
System.out.println(redisUtils.rangeZset("person", 0, -1));

5. 获取对应元素的score

/**
 * 获取对应key和value的score
 *
 * @param key
 * @param value
 * @return
 */
public Double score(String key, Object value) {
    return redisTemplate.opsForZSet().score(key, value);
}
示例代码
// 这里返回的是存入的年龄
System.out.println(redisUtils.score("person", 1287989874193399810L));
// 结果
12.0

6. 指定范围内集合排序

/**
 * 指定范围内元素排序
 *
 * @param key
 * @param v1
 * @param v2
 * @return
 */
public Set<Object> rangeByScore(String key, double v1, double v2) {
    return redisTemplate.opsForZSet().rangeByScore(key, v1, v2);
}
示例代码
// 这里返回年龄范围在10-30内的有序集合
System.out.println(redisUtils.rangeByScore("person", 10, 30));
// 结果
[1287989866203250690, 1287989874193399810, 1287989870372388866]

7. 元素score的加减

/**
 * 指定元素增加指定值
 *
 * @param key
 * @param obj
 * @param score
 * @return
 */
public Object addScore(String key, Object obj, double score) {
    return redisTemplate.opsForZSet().incrementScore(key, obj, score);
}
key和value未查询到对应的元素,会创建key及对应的value,返回的score为传入的score;存在,则直接返回修改后的score,减score直接传入负数即可。
示例代码
// 修改score前查询score值
System.out.println(redisUtils.score("person", 1287989956804411394L));
// 结果
45
// score+5,返回修改后的score
System.out.println(redisUtils.addScore("person", 1287989956804411394L, 5));
// 结果
50

8. 元素在集合内对应的排名

/**
 * 排名
 *
 * @param key
 * @param obj
 * @return
 */
public Object rank(String key, Object obj) {
    return redisTemplate.opsForZSet().rank(key, obj);
}
key和value未查询到对应的元素,返回null;存在,则直接返回元素对应的位置,从0开始,返回0,表示在第一位。
示例代码
System.out.println(redisUtils.rank("person", 1287989866203250690L));
# 结果
0