Redis简单介绍

Redis的Java客户端-SpringDataRedis


SpringData是Spring中数据操作的模块,包含对各种数据库的集成,其中对Redis的集成模块就叫做SpringDataRedis。

  • 提供了对不同Redis客户端的整合(Lettuce和Jedis)
  • 提供了RedisTemplate统一API来操作Redis
  • 支持Redis的发布订阅模型
  • 支持Redis哨兵和Redis集群
  • 支持基于Lettuce的响应式编程
  • 支持基于JDK.JSON.字符串.Spring对象的数据序列化及反序列化
  • 支持基于Redis的JDKCollection实现

SpringDataRedis中提供了RedisTemplate工具类,其中封装了各种对Redis的操作。并且将不同数据类型的操作API封装到了不同的类型中:

image-20240727151525392

1. 快速入门


SpringBoot已经提供了对SpringDataRedis的支持,使用非常简单:

1.1 导入pom坐标

1
2
3
4
5
6
7
8
9
10
11
<!--redis依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--common-pool-->
<!-- 不管是jedis还是lettuce,底层都是基于commons-pool实现连接池效果 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>

1.2 配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
spring:
data:
redis:
host: localhost
port: 6379
password: null
lettuce:
pool:
max-active: 8 #最大连接数
max-idle: 8 #最大空闲等待数
min-idle: 1 #最小空闲等待数
max-wait: 100 #连接等待时间
database: 0 #使用0号数据库
# SpringData实现了jedis和lettuce,但是默认使用的是lettuce,所以要使用jedis除了要这样配置之外还要添加依赖。

1.3.测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@SpringBootTest
class RedisTest {

@Autowired
private RedisTemplate redisTemplate;

@Test
public void testPojo(){
User user = new User("白山茶",26);
// 存入数据
redisTemplate.opsForValue().set("user:camellia",user);
// 获取数据
Object o = redisTemplate.opsForValue().get("user:camellia");
System.out.println(o);
}
}

[!tip]

SpringDataRedis的使用步骤:

  1. 引入spring-boot-starter-data-redis依赖和commons-pool2依赖
  2. 在application.yml配置Redis信息
  3. 注入RedisTemplate

2. 数据序列化器


RedisTemplate可以接收任意Object作为值写入Redis:

只不过写入前会把Object序列化为字节形式,默认是采用JDK序列化,得到的结果是这样的:

缺点:

  • 可读性差,序列化可能导致key不正确。
  • 内存占用较大

2.1 自定义RedisTemplate的序列化

  • 复杂数据结构: 如果需要存储复杂的数据结构或者自定义对象,推荐使用GenericJackson2JsonRedisSerializer。它支持对象的序列化和反序列化,便于后续的数据操作。

  • 简单字符串: 如果只是存储简单的字符串数据,可以使用RedisStringSerializer,它更简单高效。

image-20240727152837289
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Configuration
public class RedisConfig {

@Bean
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory connectionFactory){
//创建RedisTemlplate对象
RedisTemplate<String, Object> template = new RedisTemplate<>();
//设置连接工厂
template.setConnectionFactory(connectionFactory);
//创建JSON序列化工具
GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
//设置key的序列化
template.setKeySerializer(RedisSerializer.string());
template.setHashKeySerializer(RedisSerializer.string());
//设置value的序列化
template.setValueSerializer(genericJackson2JsonRedisSerializer);
template.setHashValueSerializer(genericJackson2JsonRedisSerializer);
//返回
return template;
}
}

RedisSerializer.string() 是 Spring Data Redis 提供的一个序列化器方法,它返回一个 StringRedisSerializer 实例。

这里采用了JSON序列化来代替默认的JDK序列化方式。最终结果如图:

image-20240728235812681

整体可读性有了很大提升,并且能将Java对象自动的序列化为JSON字符串,并且查询时能自动把JSON反序列化为Java对象。不过,其中记录了序列化时对应的class名称,目的是为了查询时实现自动反序列化。这会带来额外的内存开销。

2.2 StringRedisTemplate

尽管JSON的序列化方式可以满足我们的需求,但依然存在一些问题,如图:

image-20240728235812681

为了在反序列化时知道对象的类型,JSON序列化器会将类的class类型写入json结果中,存入Redis,会带来额外的内存开销。

为了减少内存的消耗,我们可以采用手动序列化的方式,换句话说,就是不借助默认的序列化器,而是我们自己来控制序列化的动作,同时,我们只采用String的序列化器,这样,在存储value时,我们就不需要在内存中就不用多存储数据,从而节约我们的内存空间。

1653054744832

这种用法比较普遍,因此SpringDataRedis就提供了RedisTemplate的子类:StringRedisTemplate,它的key和value的序列化方式默认就是String方式。

省去了自定义RedisTemplate的序列化方式的步骤,而是直接使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@SpringBootTest
class RedisTest {

// Spring Data Redis 提供的模板类,用于操作 Redis
@Autowired
private StringRedisTemplate stringRedisTemplate;

//Jackson 提供的对象映射器,用于 JSON 与对象之间的转换
private static final ObjectMapper mapper = new ObjectMapper();

@Test
public void testStringRedisTemplate() throws JsonProcessingException {
// 创建一个 User 对象
User user = new User("渡渡鸟", 21);
// 将 User 对象转换为 JSON 字符串
String json = mapper.writeValueAsString(user);
// 使用 StringRedisTemplate 将 JSON 字符串存储到 Redis 中,键为 "user:duduniao"
stringRedisTemplate.opsForValue().set("user:duduniao", json);
// 从 Redis 中获取存储的 JSON 字符串,键为 "user:duduniao"
json = stringRedisTemplate.opsForValue().get("user:duduniao");
// 将 JSON 字符串反序列化为 User 对象
User clazzUser = mapper.readValue(json, User.class);
// 打印反序列化后的 User 对象
System.out.println(clazzUser);
}
}

image-20240729005137814

最后实现JSON序列化器不将类的class类型写入json结果中。

2.3总结

RedisTemplate的两种序列化实践方案:

  1. 方案一:

    • 自定义RedisTemplate
    • 修改RedisTemplate的序列化器为GenericJackson2JsonRedisSerializer
  2. 方案二:

    • 使用StringRedisTemplate
    • 写入Redis时,手动把对象序列化为JSON。
    • 读取Redis时,手动把读取到的JSON反序列化为对象。