Appearance
Spring Data Redis
Spring Data Redis 简介
Redis 是一个基于内存的数据结构存储系统,它可以用作数据库或者缓存。它支持多种类型的数据结构,这些数据结构类型分别为 String(字符串)、List(列表)、Set(集合)、Hash(散列)和 Zset(有序集合)。
Spring Data Redis 的作用是通过一段简单的配置即可访问 redis 服务,它的底层是对 java 提供的 redis 开发包(比如 jedis 等)进行了高度封装,主要提供了如下功能:
- 连接池自动管理,提供了一个高度封装的
RedisTemplate类,基于这个类的对象可以对 redis 进行各种操作 - 针对 jedis 客户端中大量 api 进行了归类封装,将同一类型操作封装为
*Operations系列的接口ValueOperations:简单字符串类型数据操作SetOperations:set 类型数据操作ZSetOperations:zset 类型数据操作HashOperations:map 类型的数据操作ListOperations:list 类型的数据操作
Spring Data Redis 快速入门案例
Redis 环境搭建
- Redis 的测试环境搭建,详见 《Redis 安装笔记》 章节
- Redis 的基础使用,详见 《Redis 基础笔记》 章节
创建案例项目
引入依赖
创建 maven 项目 spring-data-redis,依赖相关依赖
xml
<dependencies>
<!-- jedis 客户端依赖 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.3</version>
</dependency>
<!-- Spring Data Redis 依赖 -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>2.1.8.RELEASE</version>
</dependency>
<!-- 测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.6.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
</dependencies>创建配置文件
在 resources 目录创建 applicationContext-redis.xml 配置文件
xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置 Jedis 连接池参数 -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<!-- 最大连接数 -->
<property name="maxTotal" value="30"/>
<!-- 最大空闲连接数 -->
<property name="maxIdle" value="20"/>
<!-- 最小空闲连接数 -->
<property name="minIdle" value="10"/>
<!-- 连接时的最大等待毫秒数 -->
<property name="maxWaitMillis" value="3000"/>
<!-- 在提取一个 jedis 实例时,是否提前进行验证操作;如果为 true,则得到的 jedis 实例均是可用的 -->
<property name="testOnBorrow" value="false"/>
</bean>
<!-- 配置 Jedis 连接工厂 -->
<bean id="jedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:hostName="192.168.106.128" p:port="6379" p:poolConfig-ref="jedisPoolConfig"
/>
<!-- 配置 RedisTemplate -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<!-- 配置 jedis 的连接工厂,目的是为了获取 jedis 连接 -->
<property name="connectionFactory" ref="jedisConnectionFactory"/>
</bean>
</beans>测试
创建测试类,完成一条简单数据的存取
java
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-redis.xml") // 加载配置文件
public class RedisBasicTest {
@Autowired
private RedisTemplate redisTemplate;
@Test
public void testSave() {
// 获取操作简单字符串类型数据的数据句柄
ValueOperations<String, String> ops = redisTemplate.opsForValue();
// 存入数据
ops.set("SpringDataRedisTest1", "MooNkirA");
// 查询数据
String value = ops.get("SpringDataRedisTest");
System.out.println("查询的数据:" + value);
}
}Spring Data Redis 的序列化器
通过 Redis 提供的客户端查看入门案例中存入 redis 的数据。会发现,存入的数据并不是简单的字符串,而是一些类似于二进制的数据

因为 Spring Data Redis 在保存数据的时候,底层有一个序列化器在工作,它会将要保存的数据(键和值)按照一定的规则进行序列化操作后再进行存储。spring-data-redis 提供如下几种序列化器:
StringRedisSerializer:简单的字符串序列化GenericToStringSerializer:可以将任何对象泛化为字符串并序列化Jackson2JsonRedisSerialize:序列化对象为 json 字符串GenericJackson2JsonRedisSerializer:功能同上,但是更容易反序列化OxmSerializer:序列化对象为 xml 字符串JdkSerializationRedisSerializer:序列化对象为二进制数据
RedisTemplate 默认使用的是 JdkSerializationRedisSerializer 对数据进行序列化。
Spring Data 提供了两种方式选择不同的序列化器:
方式1:通过配置文件配置
xml
<!-- 配置 RedisTemplate -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<!-- 配置 jedis 的连接工厂,目的是为了获取 jedis 连接 -->
<property name="connectionFactory" ref="jedisConnectionFactory"/>
<!-- 指定非 hash 类型的数据序列化器 -->
<property name="keySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
</property>
<property name="valueSerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
</property>
</bean>方式2:通过 RedisTemplate 对象的方法设定
java
@Autowired
private RedisTemplate redisTemplate;
@Test
public void test() {
// 指定非 hash 类型的数据序列化器
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
// RedisTemplate 操作....
}配置后正常序列化:
Spring Data Redis 常用类型操作 API
在 Redis 中有五种常见类型,Spring Data Redis 对每一种数据类型都提供了一个 xxxOperations 的API,分别是:
ValueOperations:用来操作字符串类型数据HashOperations:用来操作 hash 类型数据ListOperations:用来操作 list 类型数据SetOperations:用来操作 set 类型数据ZSetOperations:用来操作 zset 类型数据
String 类型操作 API
操作句柄的获取
通过 RedisTemplate 实体获取到字符串类型操作句柄 ValueOperations<K, V>
java
public ValueOperations<K, V> opsForValue()常用 API(待整理)
示例
java
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-redis.xml")
public class RedisStringTest {
@Autowired
private RedisTemplate<String, String> redisTemplate;
private ValueOperations<String, String> ops;
@Before
public void init() {
// 指定非 hash 类型的数据序列化器
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
// 获取操作数据句柄
ops = redisTemplate.opsForValue();
}
/* 保存数据 */
@Test
public void testSet() {
// 存入数据
ops.set("key1", "MooNkirA");
}
/* 保存有效时间的数据 */
@Test
public void testSetWithTimeout() {
// 存入数据,有效时间为10s
ops.set("key2", "N", 10, TimeUnit.SECONDS);
}
/* 保存并替换指定范围的原值 */
@Test
public void testSetWithOffset() {
// 存入数据,从指定的索引开始替换。如果 key 值原不存在,则新增键,但值为空。
ops.set("key1", "aa", 2);
}
/* 当key不存在时保存 */
@Test
public void testSetIfAbsent() {
// 当 key 不存在时执行保存操作;当 key 存在时则什么都不做
ops.setIfAbsent("key3", "斩月");
}
/* 批量保存 */
@Test
public void testMultiSet() {
Map<String, String> map = new HashMap<>();
for (int i = 4; i < 8; i++) {
map.put("key" + i, "天锁斩月");
}
// 当 key 不存在时执行保存操作;当 key 存在时则什么都不做
ops.multiSet(map);
}
/* 追加保存 */
@Test
public void testAppend() {
// 追加保存,当key存在时,会执行追加操作;当key不存在时,会执行保存操作
ops.append("key7", "appendString");
}
/* 根据键查询 */
@Test
public void testGet() {
// 根据键获取值
String value = ops.get("key1");
System.out.println(value);
}
/* 根据键查询并对值截取 */
@Test
public void testGetSubstring() {
/*
* 首先根据 key 获取 value,然后再根据 value 进行截取,从start位置截取到end位置(包含start和end)
* K key:键
* long start:截取的开始位置
* long end:截取的结束位置
*/
String value = ops.get("key1", 1, 3);
System.out.println(value);
}
/* 批量获取 */
@Test
public void testMultiGet() {
/*
* 首先根据 key 获取 value,然后再根据 value 进行截取,从start位置截取到end位置(包含start和end)
* K key:键
* long start:截取的开始位置
* long end:截取的结束位置
*/
List<String> list = ops.multiGet(Arrays.asList("key1", "key4", "key5"));
if (list != null) {
list.forEach(System.out::println);
}
}
/* 获取 value 字符的长度 */
@Test
public void testSize() {
// 根据key获取value的长度
Long length = ops.size("key1");
System.out.println("key1的值的长度:" + length);
}
/* value 自增 */
@Test
public void testIncrement() {
String key = "testIncrement";
ops.set(key, "18");
// 默认自增 1
ops.increment(key);
System.out.println(ops.get(key)); // 结果:19
// 指定自增 5
ops.increment(key, 5);
System.out.println(ops.get(key)); // 结果:24
}
/* value 自减 */
@Test
public void testDecrement() {
String key = "testDecrement";
ops.set(key, "18");
// 默认自减 1
ops.decrement(key);
System.out.println(ops.get(key)); // 结果:17
// 指定自减 5
ops.decrement(key, 5);
System.out.println(ops.get(key)); // 结果:12
}
/* 删除单个键。字符串类型的删除是通过 redisTemplate 对象删除整个键 */
@Test
public void testDelete() {
// 删除单个键
redisTemplate.delete("testIncrement");
}
/* 批量删除多个键 */
@Test
public void testMultiDelete() {
// 删除多个键
redisTemplate.delete(Arrays.asList("key4", "key5", "key6"));
}
}Hash 类型操作 API
操作句柄的获取
通过 RedisTemplate 实体获取到 Hash 类型数据操作句柄 HashOperations<K, HK, HV>
java
public <HK, HV> HashOperations<K, HK, HV> opsForHash()H:指定键的类型HK:hash 类型值的键类型HV:hash 类型值的值类型(可以是自定义类,但此类必须实现Serializable序列化接口)
常用 API(待整理)
示例
java
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-redis.xml")
public class RedisHashTest {
@Autowired
private RedisTemplate<String, String> redisTemplate;
// private HashOperations<String, String, Object> ops;
/*
* HashOperations<H, HK, HV>
* H:指定键的类型
* HK:hash 类型值的键类型
* HV:hash 类型值的值类型(可以是自定义类,但此类必须实现 Serializable 序列化接口)
*/
private HashOperations<String, String, Student> ops;
@Before
public void init() {
// 指定非 hash 类型的数据序列化器
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer()); // hash 类型值中键的序列化类型
redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer()); // hash 类型值中值的序列化类型
// 获取操作数据句柄
ops = redisTemplate.opsForHash();
}
/* 保存数据 */
@Test
public void testPut() {
Student student = new Student();
student.setName("夜神月");
student.setAge(18);
Student student2 = new Student();
student2.setName("L");
student2.setAge(19);
ops.put("key1", "key1-1", student);
ops.put("key1", "key1-2", student2);
}
/* 判断值中的某个 hashKey 是否存在 */
@Test
public void testHasKey() {
String key = "key1";
String valueKey = "key1-2";
Boolean b = ops.hasKey(key, valueKey);
System.out.println(key + "键中的" + valueKey + "是否存在:" + b);
}
/* 根据 key 与 hashKey 获取数据 */
@Test
public void testGet() {
Student s = ops.get("key1", "key1-1");
System.out.println(s);
}
/* 获取指定 key 中所有 hashKey 的集合 */
@Test
public void testKeys() {
Set<String> keys = ops.keys("key1");
keys.forEach(System.out::println);
}
/* 获取指定 key 中所有 hashValue 的集合 */
@Test
public void testValues() {
List<Student> values = ops.values("key1");
values.forEach(System.out::println);
}
/* 获取指定 key 中所有 hash 对象的集合 */
@Test
public void testEntries() {
Map<String, Student> map = ops.entries("key1");
map.entrySet().forEach(e -> System.out.println(e.getKey() + " :: " + e.getValue()));
}
/* 根据 key 与 hashKey 删除数据 */
@Test
public void testDelete() {
// 可以删除多个数据,当 hash 类型中的数据全部被删除后,整个 hash 类型的键也被删除
Long num = ops.delete("key1", "key1-2", "key1-1");
System.out.println("成功删除的数量" + num);
}
}List 类型操作 API
操作句柄的获取
通过 RedisTemplate 实体获取到 List 类型操作句柄 ListOperations<K, V>
java
public ListOperations<K, V> opsForList()常用 API(待整理)
示例
java
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-redis.xml")
public class RedisListTest {
@Autowired
private RedisTemplate<String, String> redisTemplate;
private ListOperations<String, String> ops;
private final static String KEY = "key-list"; // 测试使用的键
@Before
public void init() {
// 指定非 hash 类型的数据序列化器
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
// 获取操作数据句柄
ops = redisTemplate.opsForList();
}
/* 左增加数据 */
@Test
public void testLeftPush() {
// 将所有指定的值插入存储在键的列表的头部(或尾部)。如果键不存在,则在执行推送操作之前将其创建为空列表。
// 从左边添加一个元素
ops.leftPush(KEY, "L");
// 从左边添加多个元素
ops.leftPushAll(KEY, "夜神月", "香风智乃", "樱木花道");
}
/* 右增加数据 */
@Test
public void testRightPush() {
// 将所有指定的值插入存储在键的列表的头部(或尾部)。如果键不存在,则在执行推送操作之前将其创建为空列表。
// 从右边添加一个元素
ops.rightPush(KEY, "流川枫");
// 从右边添加多个元素
ops.rightPushAll(KEY, "仙道彰", "路飞", "女帝波雅·汉库克");
}
/* 根据索引获取数据 */
@Test
public void testFindIndex() {
// 0和正数代表从左边开始查找,第一个元素索引是0
String val = ops.index(KEY, 1);
System.out.println("左边第2个元素是:" + val);
// 负数代表从右边开始查找,第一个元素索引是-1
String val2 = ops.index(KEY, -2);
System.out.println("右边第2个元素是:" + val2);
}
/* 根据范围获取数据 */
@Test
public void testRange() {
// 根据 key 查询一个范围(包含开始索引,结束索引),索引从0开始
List<String> range = ops.range(KEY, 1, 4);
if (range != null) {
range.forEach(System.out::println);
}
}
/* 删除左边第一个元素 */
@Test
public void testLeftLop() {
// 弹出左边第1个元素
String s = ops.leftPop(KEY);
System.out.println("删除左边第1个元素是:" + s);
}
/* 删除右边第一个元素 */
@Test
public void testRightPop() {
// 弹出右边第1个元素
String s = ops.rightPop(KEY);
System.out.println("删除右边第1个元素是:" + s);
}
/* 删除指定的元素 */
@Test
public void testRemove() {
/*
* Long remove(K key, long count, Object value)
* key:键值
* count:删除元素的个数
* count > 0:删除左边起第几个等于指定值的元素
* count < 0:删除右边起第几个等于指定值的元素
* count = 0:删除所有等于value的元素。
* value:元素值
*/
ops.remove(KEY, 1, "L");
}
}Set 类型操作 API
操作句柄的获取
通过 RedisTemplate 实体获取到 Set 类型操作句柄 SetOperations<K, V>
java
public SetOperations<K, V> opsForSet()常用 API(待整理)
示例
java
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-redis.xml")
public class RedisSetTest {
@Autowired
private RedisTemplate<String, String> redisTemplate;
private SetOperations<String, String> ops;
// 测试使用的键
private final static String KEY = "key-set";
private final static String KEY1 = "key-set1";
private final static String KEY2 = "key-set2";
@Before
public void init() {
// 指定非 hash 类型的数据序列化器
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
// 获取操作数据句柄
ops = redisTemplate.opsForSet();
}
/* 增加数据 */
@Test
public void testAdd() {
// 增加一个或多个数据,如果重复的数据不会增加
ops.add(KEY, "夜神月", "香风智乃", "樱木花道", "仙道彰", "路飞", "女帝波雅·汉库克", "夜神月");
}
/* 查询所有元素 */
@Test
public void testMembers() {
Set<String> members = ops.members(KEY);
if (members != null) {
members.forEach(System.out::println);
}
}
/* 随机获取一个元素 */
@Test
public void testRandomMember() {
String value = ops.randomMember(KEY);
System.out.println("随机获取一个元素:" + value);
}
/* 随机获取多个元素(可能会获取重复的值) */
@Test
public void testRandomMembers() {
// 随机获取多个元素,count 参数指定获取元素的个数。
List<String> randomMembers = ops.randomMembers(KEY, 3);
if (randomMembers != null) {
randomMembers.forEach(System.out::println);
}
}
/* 删除元素 */
@Test
public void testRemove() {
// 删除指定的元素,并返回成功移除的个数
Long count = ops.remove(KEY, "樱木花道", "仙道彰", "路飞");
System.out.println("成功移除的元素总数:" + count);
}
/* 随机删除元素 */
@Test
public void testPop() {
// 随机删除指定个数的元素,并返回成功移除的元素
List<String> pops = ops.pop(KEY, 2);
if (pops != null) {
pops.forEach(System.out::println);
}
}
/* 多集合操作 - 交集 */
@Test
public void testIntersect() {
ops.add(KEY1, "夜神月", "香风智乃", "樱木花道");
ops.add(KEY2, "路飞", "女帝波雅·汉库克", "夜神月");
// 获取两个key的值的交集
Set<String> result = ops.intersect(KEY1, KEY2);
if (result != null) {
result.forEach(System.out::println);
}
}
/* 多集合操作 - 并集 */
@Test
public void testUnion() {
ops.add(KEY1, "夜神月", "香风智乃", "樱木花道");
ops.add(KEY2, "路飞", "女帝波雅·汉库克", "夜神月");
// 获取两个key的值的交集
Set<String> result = ops.union(KEY1, KEY2);
if (result != null) {
result.forEach(System.out::println);
}
}
/* 多集合操作 - 差集 */
@Test
public void testDifference() {
ops.add(KEY1, "夜神月", "香风智乃", "樱木花道");
ops.add(KEY2, "路飞", "女帝波雅·汉库克", "夜神月");
/*
* 获取两个key的值的差集
* 规则是获取第一个集合中存在,但是在第二个集合中不存在的元素
*/
Set<String> result = ops.difference(KEY2, KEY1);
if (result != null) {
result.forEach(System.out::println);
}
}
}ZSet 类型操作 API
操作句柄的获取
通过 RedisTemplate 实体获取到 ZSet 类型操作句柄 ZSetOperations<K, V>
java
public ZSetOperations<K, V> opsForZSet()常用 API(待整理)
示例
java
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-redis.xml")
public class RedisZSetTest {
@Autowired
private RedisTemplate<String, String> redisTemplate;
private ZSetOperations<String, String> ops;
// 测试使用的键
private final static String KEY = "key-zset";
private final static String KEY1 = "key-zset1";
private final static String KEY2 = "key-zset2";
@Before
public void init() {
// 指定非 hash 类型的数据序列化器
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
// 获取操作数据句柄
ops = redisTemplate.opsForZSet();
}
/* 增加单个数据 */
@Test
public void testAdd() {
/*
* Boolean add(K key, V value, double score)
* key:键值
* value:值
* score:分数值,用于排名(排序)
*/
ops.add(KEY, "夜神月", 190);
ops.add(KEY, "香风智乃", 90);
ops.add(KEY, "樱木花道", 25);
ops.add(KEY, "L", 191);
ops.add(KEY, "金田一", 180);
}
/* 分数的增减 */
@Test
public void testIncrementScore() {
// incrementScore 可以用来增减分数,正数就是增加,负数则减少
// 增加分数
ops.incrementScore(KEY, "樱木花道", 10);
// 减少分数
ops.incrementScore(KEY, "香风智乃", -20);
}
/* 查询元素的分数 */
@Test
public void testScore() {
// 查询元素的分数
Double score = ops.score(KEY, "金田一");
System.out.println("分数:" + score);
}
/* 查询元素的排名 */
@Test
public void testRank() {
// 查询元素在集合中的排名,排名从0开始
Long rank = ops.rank(KEY, "夜神月");
System.out.println("排名:" + rank);
}
/* 列表查询:分为两大类,正序和逆序。以下只列表正序的,逆序的只需在方法前加上reverse即可 */
/* 根据排名区间来获取元素列表 */
@Test
public void testRange() {
// 正序根据排名区间来获取元素列表,包含开始与结束索引,索引从0开始
Set<String> range = ops.range(KEY, 0, 2);
if (range != null) {
range.forEach(System.out::println);
}
// 逆序根据排名区间来获取元素列表,包含开始与结束索引,索引从0开始
Set<String> reverseRange = ops.reverseRange(KEY, 0, 2);
if (reverseRange != null) {
reverseRange.forEach(System.out::println);
}
}
/* 根据分数排序区间来获取元素列表 */
@Test
public void testRangeWithScores() {
// 正序根据分数排序区间来获取元素列表,包含开始与结束索引,索引从0开始
Set<ZSetOperations.TypedTuple<String>> typedTuples = ops.rangeWithScores(KEY, 1, 3);
if (typedTuples != null) {
typedTuples.forEach(i -> {
System.out.println("值:" + i.getValue() + ";分数:" + i.getScore());
});
}
// 逆序根据分数排序区间来获取元素列表,包含开始与结束索引,索引从0开始
Set<ZSetOperations.TypedTuple<String>> reverseTypedTuples = ops.reverseRangeWithScores(KEY, 1, 3);
if (reverseTypedTuples != null) {
reverseTypedTuples.forEach(i -> {
System.out.println("值:" + i.getValue() + ";分数:" + i.getScore());
});
}
}
/* 根据分数范围来获取元素列表 */
@Test
public void testRangeByScore() {
// 正序根据指定的最小分数与最大分数范围来获取元素列表(包含最小和最大值)
Set<String> range = ops.rangeByScore(KEY, 70, 180);
if (range != null) {
range.forEach(System.out::println);
}
// 逆序根据指定的最小分数与最大分数范围来获取元素列表(包含最小和最大值)
Set<String> reverseRange = ops.reverseRangeByScore(KEY, 70, 180);
if (reverseRange != null) {
reverseRange.forEach(System.out::println);
}
}
/* 根据分数范围来获取元素和分数列表 */
@Test
public void testRangeByScoreWithScores() {
// 正序根据指定的最小分数与最大分数范围来获取元素和分数列表(包含最小和最大值)
Set<ZSetOperations.TypedTuple<String>> typedTuples = ops.rangeByScoreWithScores(KEY, 70, 190);
if (typedTuples != null) {
typedTuples.forEach(i -> System.out.println("值:" + i.getValue() + ";分数:" + i.getScore()));
}
// 逆序根据指定的最小分数与最大分数范围来获取元素和分数列表(包含最小和最大值)
Set<ZSetOperations.TypedTuple<String>> reverseTypedTuples = ops.reverseRangeByScoreWithScores(KEY, 70, 190);
if (reverseTypedTuples != null) {
reverseTypedTuples.forEach(i -> System.out.println("值:" + i.getValue() + ";分数:" + i.getScore()));
}
}
/* 统计集合大小 */
@Test
public void testZCard() {
// 统计指定的键的集合大小
Long zCard = ops.zCard(KEY);
System.out.println("集合大小:" + zCard);
}
/* 统计分数区间的元素数量 */
@Test
public void testCount() {
// 根据指定的最小分数与最大分数范围来统计元素的数量(包含最小和最大值)
Long count = ops.count(KEY, 70, 190);
System.out.println("70~190分数的元素总计:" + count);
}
/* 删除指定的元素 */
@Test
public void testRemove() {
// 删除指定单个或者多个元素
ops.remove(KEY, "L", "夜神月");
}
/* 根据排名区间删除元素 */
@Test
public void testRemoveRange() {
// 根据排名区间删除,排名是从0开始
ops.removeRange(KEY, 0, 2);
}
/* 根据分数区间删除元素 */
@Test
public void testRemoveRangeByScore() {
// 根据指定的最小分数与最大分数区间删除元素,包含最小值和最大值
ops.removeRangeByScore(KEY, 90, 190);
}
}Spring Data Redis 原理分析
RestTemplate 底层实现
Spring Data Redis 操作 Redis 服务器只要是通过 RestTemplate 实现的。下面通过源码追踪的形式来查阅 RestTemplate 底层到底是如何操作 redis
- 首先看配置文件中关于
RestTemplate的 bean 的配置,可以看到在RedisTemplate的 bean 声明中注入了一个JedisConnectionFactory实例,这个连接工厂是用来获取 Jedis 连接的,那么通过这种方式RedisTemplate就可以拿到操作 Redis 服务器的句柄了。

- 使用 debug 运行入门案例,观察创建好的
RestTemplate实例,可以看到里面主要有序列化器和 redis 的连接信息,

- 跟踪进入
set方法,可以看到set方法中使用了一个connection实例来进行操作,此connection的类型是JedisConnetion,而这个connection实例肯定是通过配置文件配置的JedisConnectionFactory产生的,也就是底层开始调用 jedis 的 api 了。

- 继续追踪
set方法,选择JedisStringCommands实现

- 继续跟踪
set方法,可以看到底层已经获取到了 jedis 的实例,再调用set方法已经在调 jedis 的set方法了

- 再往下追踪,就会发现底层最终调用的是 jedis 的原生 API
setCommand方法,这个方法就是 jedis 提供的对 redis 的各种操作命令了。

结论:Spring Data 提供 RedisTemplate 就是在原生的 Jedis 或者其他操作 redis 的技术上做的一层封装,它屏蔽掉了这些原生技术的实现细节,统一了调用接口,使得操作更加简单明了。