集成Redis及注意事项
# 集成Redis及注意事项
redis作为一个常用的中间件,学会在SpringBoot应用中使用它,是很重要的,下面就介绍如何引入和使用,以及一些注意事项。
# 引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 连接池支持(可选) -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
2
3
4
5
6
7
8
9
关于如何使用Jedis、Lettuce这里就不展开了,在介绍Redis的客户端那一篇中有详细说明。
spring-boot-starter-data-redis
:包含 Spring Data Redis 的核心功能,默认使用 Lettuce。commons-pool2
:用于 Lettuce 连接池管理。
# 配置链接
在 application.yml
中配置 Redis 服务器信息和连接池参数:
spring:
data:
redis:
host: 127.0.0.1
port: 6379
password: 123456
database: 0
timeout: 5000ms # 连接超时时间
lettuce:
pool:
max-active: 10 # 最大连接数(推荐:CPU * 2 + 2)
max-idle: 8 # 最大空闲连接数(推荐:CPU * 2)
min-idle: 2 # 最小空闲连接数
max-wait: 2000ms # 获取连接的最大等待时间
2
3
4
5
6
7
8
9
10
11
12
13
14
# 使用
# 自定义 RedisTemplate
Spring Data Redis 提供了 RedisTemplate
和 StringRedisTemplate
,但默认的 RedisTemplate
使用 JDK 序列化(不推荐),需要自定义配置以支持对象存储。
下列为一个参考示例:
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// 设置 Key 和 HashKey 的序列化方式为 String
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
// 设置 Value 和 HashValue 的序列化方式为 JSON
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
return template;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
默认 JdkSerializationRedisSerializer
会产生二进制乱码,推荐 JSON 序列化。
GenericJackson2JsonRedisSerializer
:将 Java 对象序列化为 JSON,可读性强且支持跨语言兼容。StringRedisSerializer
:用于字符串类型的 Key。JdkSerializationRedisSerializer
:不推荐使用(生成的 Key 是乱码)。
# 为什么要序列化
为什么要对 RedisTemplate 进行序列化?
Redis 是一个键值数据库,它只能存储 字节数组(byte[])。Java 对象(如 POJO、List、Map 等)无法直接存储到 Redis 中,必须通过 序列化器(Serializer) 将对象转换为字节数组,再反向操作将字节数组还原为 Java 对象。
# 核心原因
- 数据格式兼容性:
- Redis 的 Key 和 Value 都是字节数组,Java 对象必须通过序列化器转换为字节数组才能存储。
- 跨语言支持:
- 如果 Redis 需要与其他语言(如 Python、Node.js)交互,使用 JSON 格式序列化可以保证数据可读性和兼容性。
- 调试与监控:
- 使用可读的序列化格式(如 JSON)可以方便地通过 Redis 客户端(如
redis-cli
)查看存储的数据。
- 使用可读的序列化格式(如 JSON)可以方便地通过 Redis 客户端(如
# 不序列化的问题
Spring Data Redis 默认使用 JDK 序列化器,但存在以下问题:
- 可读性差:存储的数据是二进制格式,通过
redis-cli
查看时会显示乱码。
"rO0ABXNyABFqYXZheC5sZXZlbC5UZXN0TGV2ZWwK..."
- 跨语言不兼容:其他语言无法解析 JDK 序列化的数据。
- 类版本问题:如果修改了 Java 类的结构(如增删字段),反序列化会失败。
存储复杂对象的混乱
如果直接存储对象(如 User user = new User("Alice", 25);
),未配置序列化器会导致:
- 存储的 Key 和 Value 是乱码。
- 无法通过 Redis 客户端直接查看或调试数据。
性能问题
- JDK 序列化器的性能较低,且生成的字节数组较大,占用更多内存和网络带宽。
# RedisTemplate 支持哪些序列化方式?
# StringRedisSerializer
- 用途:序列化字符串(String)类型的数据。
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new StringRedisSerializer());
2
# GenericJackson2JsonRedisSerializer
- 用途:序列化复杂对象(POJO、List、Map 等)为 JSON 格式。
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
# Hash 结构的序列化
- Hash Key/Value 的独立配置:
- 可以分别为 Hash 的 Key 和 Value 配置不同的序列化器。
- 例如:Hash 的 Key 使用
StringRedisSerializer
,Value 使用GenericJackson2JsonRedisSerializer
。
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
2
最后总结下:
问题 | 解决方案 |
---|---|
为什么要序列化? | Redis 只能存储字节数组,Java 对象需通过序列化器转换。 |
不序列化有什么问题? | 默认 JDK 序列化器导致数据不可读、跨语言不兼容、类版本问题。 |
常见序列化方式有哪些? | StringRedisSerializer 、GenericJackson2JsonRedisSerializer 、Protobuf 等。 |
每种数据类型都需要序列化吗? | 简单类型(String、Number)无需序列化,复杂类型(POJO、Hash)必须配置。 |
# 扩展-FastJson进行序列化
除了使用jackson进行序列化,还可以使用FastJson进行序列化。
使用 FastJson 作为 RedisTemplate 的序列化器,替代 GenericJackson2JsonRedisSerializer
(基于 Jackson)。以下是具体实现方式和注意事项:
- 引入依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version> <!-- 使用最新稳定版本 -->
</dependency>
2
3
4
5
- 自定义 FastJsonRedisSerializer
创建自定义的 Redis 序列化器类,实现 RedisSerializer
接口:
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import java.nio.charset.StandardCharsets;
public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
private final Class<T> clazz;
public FastJsonRedisSerializer(Class<T> clazz) {
this.clazz = clazz;
}
@Override
public byte[] serialize(T value) throws SerializationException {
if (value == null) {
return new byte[0];
}
// 将对象转换为 JSON 字符串,并写入类名(可选)
String json = JSON.toJSONString(value,
SerializerFeature.WriteClassName); // 写入类名,用于反序列化
return json.getBytes(StandardCharsets.UTF_8);
}
@Override
public T deserialize(byte[] bytes) throws SerializationException {
if (bytes == null || bytes.length == 0) {
return null;
}
String json = new String(bytes, StandardCharsets.UTF_8);
return JSON.parseObject(json, clazz);
}
}
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
28
29
30
31
32
33
34
35
- 配置 RedisTemplate
在 Spring Boot 配置类中,覆盖默认的 RedisTemplate
配置:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// Key 和 Hash Key 使用 StringRedisSerializer
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
// Value 和 Hash Value 使用 FastJsonRedisSerializer
template.setValueSerializer(new FastJsonRedisSerializer<>(Object.class));
template.setHashValueSerializer(new FastJsonRedisSerializer<>(Object.class));
return template;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
通过自定义 FastJsonRedisSerializer
,可以灵活控制序列化行为(如类名、循环引用等)。
在配置时注意泛型类型匹配和编码方式(推荐 UTF-8),以确保数据正确存储和读取。
# 自定义连接池配置
Lettuce 的连接池基于 LettucePoolingClientConfiguration
,可通过以下方式进一步优化:(可选)
@Bean
public RedisConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
config.setHostName("127.0.0.1");
config.setPort(6379);
config.setPassword("123456");
LettucePoolingClientConfiguration poolingConfig = LettucePoolingClientConfiguration.builder()
.poolConfig(new GenericObjectPoolConfig<>())
.commandTimeout(Duration.ofSeconds(5))
.build();
return new LettuceConnectionFactory(config, poolingConfig);
}
2
3
4
5
6
7
8
9
10
11
12
13
14