Spring Data Redis
Redis是一个基于Key-Value形式的非关系型内存数据库,主要用作高性能缓存和存储一些临时信息。Java程序中操作Redis数据库有Jedis、Redisson、Lettuce等客户端可以直接使用,而在使用Spring框架时,Spring Data Redis项目提供了RedisTemplate,它为我们进一步封装了Redis客户端,Jedis、Redisson等客户端库都支持集成Spring Data Redis,因此使用Spring Data Redis我们可以在这些客户端之间无缝切换,Spring生态下的很多库也都依赖Spring Data Redis,使用它能起到增强程序代码可移植性的目的。
引入Maven依赖
对于传统Spring工程
对于非SpringBoot工程,引入Spring Data Redis有点复杂,我们要考虑引入Maven依赖的版本兼容性问题。Spring Data Redis中,1.x和2.x有不兼容的API,这里我们使用2.x版本。
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>2.7.0</version>
</dependency>
Lettuce、Jedis等客户端都能够很方便的集成到Spring中,这里我们选择Lettuce。
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>6.1.8.RELEASE</version>
</dependency>
存取对象时Spring Data Redis默认用了Java的序列化机制,但如果需要存储的文本有一定的可读性,对象序列化建议改为JSON方式,Spring Data Redis内置支持Jackson序列化器。
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.13.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.13.3</version>
</dependency>
对于SpringBoot工程
如果是SpringBoot环境,集成Spring Data Redis只需要引入一个起步依赖即可。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
配置文件
在非SpringBoot环境下,使用RedisTemplate前我们需要在Spring配置文件中配置相关的Bean。RedisTemplate需要通过一个RedisConnectionFactory对象配置,支持该对象的Redis客户端都可以配置为RedisTemplate的底层客户端。在最新版本中,官方推荐使用Lettuce作为客户端。
applicationContext.xml
<!-- 配置Lettuce客户端 -->
<bean id="lettuceConnectionFactory" class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory">
<property name="hostName" value="127.0.0.1" />
<property name="port" value="6379" />
</bean>
<!-- 配置Spring Data Redis -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="lettuceConnectionFactory" />
</bean>
SpringBoot环境下就非常简单了,我们只需要一些简洁的配置,例子如下。
application.properties
spring.redis.host=127.0.0.1
spring.redis.port=6379
Lettuce客户端还有很多其他参数,比如连接的数据库序号、密码等,以及集群模式支持,具体可以参考Lettuce相关章节。
RedisTemplate简单使用
下面例子代码我们使用Spring Data Redis存取一个字符串数据。
Main.java
package com.gacfox.demoredis;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取RedisTemplate的Bean
RedisTemplate<String, String> redisTemplate = (RedisTemplate<String, String>) context.getBean("redisTemplate");
// 获取ValueOperations操作对象
ValueOperations<String, String> vops = redisTemplate.opsForValue();
// 向Redis写入值
vops.set("str", "hello, world!");
// 从Redis获取值
String s = vops.get("str");
System.out.println(s);
}
}
代码非常简单,我们从Spring的ApplicationContext中获得我们之前XML中配置好的bean,RedisTemplate中有一组方法opsFor*专门用于操作Redis的各种数据结构,我们获取*Operations对象调用其中的方法即可。
注意:上面代码我们直接从Spring应用上下文中获取了redisTemplate对象,实际使用中,我们一般都是通过依赖注入的方式使用。
自定义类型的Redis存取
上面例子中我们可以看到RedisTemplate是支持泛型的,下面代码演示实例化一个自定义的Java对象,存入Redis再取出。
package com.gacfox.demoredis;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
RedisTemplate<String, Student> redisTemplate = (RedisTemplate<String, Student>) context.getBean("redisTemplate");
Student s = new Student();
s.setName("Alice");
s.setAge(18);
ValueOperations<String, Student> vops = redisTemplate.opsForValue();
vops.set("student", s);
vops.get("student");
}
}
这里要注意的是,我们必须为要存储的类实现Serializable接口,这样该对象才能够成功进行序列化并存入Redis数据库中,在Redis中序列化后的对象使用string类型进行存储。除此之外,一个可序列化对象引用其他多个可序列化对象,也是能够成功存入Redis中的,总之只要能够成功进行Java对象序列化,就能存入Redis中。
序列化器配置
Spring Data Redis默认使用Java自带的对象序列化机制,之前例子即使我们存储的只是一个简单的String类型,但是实际上存入Redis中的内容可能和我们想象的不太相同。
vops.set("str", "hello, world!");
Redis中实际的存储结果并不是键值对"str"和"hello, world!",我们可以在redis-cli中使用keys *进行查询,得到的键大概是这样的。
"\xac\xed\x00\x05t\x00\x03str"
再查询键对应的值,结果可能如下。
127.0.0.1:6379> get "\xac\xed\x00\x05t\x00\x03str"
"\xac\xed\x00\x05t\x00\rhello, world!"
这是因为Spring Data Redis底层默认使用JDK的序列化机制,包括String类型也会采用这种序列化机制。JDK序列化的优点是性能较好,但如果为了存取的数据具有更好的可读性,我们可以为RedisTemplate手动指定JSON类型的序列化器。
对于普通传统Spring工程,我们可以按如下配置RedisTemplate这个Bean,对于SpringBoot工程我们替换为等效的JavaConfig即可。
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="lettuceConnectionFactory" />
<property name="keySerializer">
<bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer " />
</property>
<property name="valueSerializer">
<bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer " />
</property>
<property name="hashKeySerializer">
<bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer " />
</property>
<property name="hashValueSerializer">
<bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer " />
</property>
</bean>
GenericJackson2JsonRedisSerializer是支持类型的JSON序列化器,其输出例子如下。
{
"@class": "com.gacfox.demoredis.Student",
"name": "Alice",
"age": 18
}
自动生成的@class键指定了JSON对象节点需要反序列化的Java类型。除了GenericJackson2JsonRedisSerializer,Spring Data Redis还有一个Jackson2JsonRedisSerializer比较常用,它存储的就是JSON纯文本,对象一旦存入后,就只能手动以字符串形式取出,并手动调用JSON反序列化器得到对象。
有关其他Redis数据类型的操作
Redis提供了5种灵活的数据结构供我们使用,在RedisTemplate中都能够找到对应的操作方法:
opsForValue():存取字符串(配置序列化器后,存取Java对象会自动序列化和反序列化为字符串)
opsForHash():存取哈希对象
opsForList():存取列表
opsForSet():存取集合对象
OpsForZSet():存取有序集合对象
从日常开发角度来看,前两种是最为常用的。这些内容都比较简单,这里就不赘述了。