• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 众包
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

colir0

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

JAVA21+Springboot3整合redis——解决乱码问题

这几天为了准备面试,重新对redis的相关知识进行的回顾。redis作为项目开发中常用的之间件,是面试中必不可少的面试考点,对redis的使用也是不能生疏滴~~

前置知识

Java21 + Springboot整合redis这里使用的是spring data redis,在解决问题之前,我们需要先将spring data redis相关的依赖配置设置好。

  1. 引入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连接,从而提高应用程序的性能和效率

  1. 配置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(负值表示没有限制)
  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 : "王五" 的数据,并进行获取,
image
接下来我再在springboot写入更新name的数据,为 "张三"。
image
image
控制台打印出来的数据确实是张三。好的,接下来我们再回答redis客户端去获取我的name数据。
image

问题来了,在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采用的序列化器的属性定义。
image

redisTemlate 使用的默认序列化器是什么? 我们看一下下面的代码

if (this.defaultSerializer == null) {
     this.defaultSerializer = new JdkSerializationRedisSerializer(this.classLoader != null ? this.classLoader : this.getClass().getClassLoader());
}

不难看出redisTemplate默认使用的序列化工具是JdkSerializationRedisSerializer

同样的,我们也可以使用debbug方式进行调试,更为直观。
image
image
它会将我们的value转换成字节码的格式,我进入它的这个详细的方法看一下
image

image
好的最终很明显啦,就是进入了这个jdk的序列化器。那么使用这个jdk的序列化器会带来什么问题?

坏处:
1. 可读性差
2. 内存占用大
3. 出现乱码问题


解决方法: 配置更改序列化器

来看一下我们都有哪些序列化器
image
我们可以这么认为 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);
    }

出现一个小错误,我们看一下,下面说缺少一个类,那我们就加上就欧克啦
image

在pom配置文件添加一下下面的依赖

<dependency>
     <groupId>com.fasterxml.jackson.core</groupId>
     <artifactId>jackson-databind</artifactId>
</dependency>

解决完后我们继续执行,好嘟执行成功如下
image
好嘟,我现在回到客户端再次查看一下我的name(原来的name在redis客户端是“王五”)
image
哦耶!!!最新输入的name被修改啦!!

posted on 2024-03-16 00:39  colir0  阅读(309)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3