JAVA21+Springboot3整合redis——解决乱码问题
前置知识
Java21 + Springboot整合redis这里使用的是spring data redis,在解决问题之前,我们需要先将spring data redis相关的依赖配置设置好。
- 引入spring data redis的maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 引入我们的一个连接线 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.11.1</version>
</dependency>
这里解释一下为什么需要引入连接池,在springboot使用redis,我们需要创建一个redis连接来与redis服务器进行通信。如果每一次我们去使用redis都要去创建一个连接的话,就会带来额外的开销,这对性能是不友好的,那么引入我们的连接池对redis的连接进行管理,避免频繁的创建和销毁redis连接,从而提高应用程序的性能和效率
- 配置redis相关配置信息
spring:
data:
redis:
host: localhost # Redis服务器地址
port: 6379 # Redis服务器连接端口
password: xxxxxx # Redis服务器连接密码(默认为空)
database: 0 # Redis数据库索引(默认为0)
timeout: 60s # 连接空闲超过N(s秒、ms毫秒,不加单位时使用毫秒)后关闭,0为禁用,这里配置值和tcp-keepalive值一致
# Lettuce连接池配置
lettuce:
pool:
max-active: 10 # 允许最大连接数,默认8(负值表示没有限制),推荐值:大于cpu * 2,通常为(cpu * 2) + 2
max-idle: 8 # 最大空闲连接数,默认8,推荐值:cpu * 2
min-idle: 0 # 最小空闲连接数,默认0
max-wait: 5s # 连接用完时,新的请求等待时间(s秒、ms毫秒),超过该时间抛出异常,默认-1(负值表示没有限制)
- 测试
在springboot的测试环境中注入RedisTemplate(这里就用到了springboot的自动装配实现的,后面的合集中讲到),就可以使用了,下面是一个简单的例子。
@Autowired
private RedisTemplate redisTemplate;
@Test
void contextLoads() {
redisTemplate.opsForValue().set("study:test:string:name","张三");
Object name = redisTemplate.opsForValue().get("study:test:string:name");
System.out.println("name:"+name);
}
Redis 乱码问题 (案例引入)
下面给大家带来一个简单的例子:
我们现在redis客户端写入一个name : "王五" 的数据,并进行获取,

接下来我再在springboot写入更新name的数据,为 "张三"。


控制台打印出来的数据确实是张三。好的,接下来我们再回答redis客户端去获取我的name数据。

问题来了,在springboot中我们去get这个name是可以获取到 “张三” 这个数据的,但是我们再去redis客户端去get这个name按理说应该是“张三”的,为什么不是呢?
Spring Boot整合Redis出现乱码的原因可能是由于RedisTemplate默认使用的序列化器与实际需求不符。RedisTemplate默认使用的是JDK序列化器,而它使用的编码是ISO-8859-1,这可能导致在存储和读取中文字符时出现乱码。
springboot整合redis出现乱码的原因(源码上看一下)
// redisTemplate 默认开启默认属性
private boolean enableDefaultSerializer = true;
// redisTemlate 使用的默认属性
@Nullable
private RedisSerializer<?> defaultSerializer;
我们利用springboot整合的redis进行数据的存储,最终都会被序列化,下面是redisTemplate工具中对key,value,hashkey,hashvalue采用的序列化器的属性定义。

redisTemlate 使用的默认序列化器是什么? 我们看一下下面的代码
if (this.defaultSerializer == null) {
this.defaultSerializer = new JdkSerializationRedisSerializer(this.classLoader != null ? this.classLoader : this.getClass().getClassLoader());
}
不难看出redisTemplate默认使用的序列化工具是JdkSerializationRedisSerializer
同样的,我们也可以使用debbug方式进行调试,更为直观。


它会将我们的value转换成字节码的格式,我进入它的这个详细的方法看一下


好的最终很明显啦,就是进入了这个jdk的序列化器。那么使用这个jdk的序列化器会带来什么问题?
坏处:
1. 可读性差
2. 内存占用大
3. 出现乱码问题
解决方法: 配置更改序列化器
来看一下我们都有哪些序列化器

我们可以这么认为 JdkSerializationRedisSerializer 是最差的一种序列化器,我们一般不去使用它,那么我们还可以使用哪种序列化器,显然我上面标红了,我们的 StringRedisSerializer 。StringRedisSerialize 一般用于我们的key序列化,主要是我们的key一般都是字符串类型的,那对于我们的value一般使用上面序列化器呢?我们知道redis可以存储多种数据类型,其value可以是对象,也可以是数组,也可以是字符串等等。争对这种情况,我们使用GenericJackson2JsonRedisSerialize序列化器。
下面我通过自定义的方式去实现我的自定义序列化器,redis去实现我们自定义的序列化器可以看成4步
- [创建Template]
- [设置连接工厂]
- [设置序列化工具]
- [针对key,value采用不同的序列化器]
工具上面的步骤我们开始代码的编写,首先我们需要自定义一个redis的配置类RedisConfig,然后对RedisTemplate自定义实现,代码如下
@Bean
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
// 创建Template
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
// 设置连接工厂
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 设置序列化工具
GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
// key 和 hashkey采用String序列化
redisTemplate.setKeySerializer(RedisSerializer.string());
redisTemplate.setHashKeySerializer(RedisSerializer.string());
// value 和 hashValue采用json序列化
redisTemplate.setValueSerializer(jsonRedisSerializer);
redisTemplate.setHashValueSerializer(jsonRedisSerializer);
return redisTemplate;
}
测试
@Test
void contextLoads() {
redisTemplate.opsForValue().set("name","张三");
Object name = redisTemplate.opsForValue().get("name");
System.out.println("name:"+name);
}
出现一个小错误,我们看一下,下面说缺少一个类,那我们就加上就欧克啦

在pom配置文件添加一下下面的依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
解决完后我们继续执行,好嘟执行成功如下

好嘟,我现在回到客户端再次查看一下我的name(原来的name在redis客户端是“王五”)

哦耶!!!最新输入的name被修改啦!!
浙公网安备 33010602011771号