SpringDataRedis存储Redis的数据序列化

在使用Spring Data Redis存储数据至Redis时,选择合适的序列化策略至关重要。它不仅影响数据存储的效率和空间利用率,还关系到跨语言兼容性和系统的扩展性。适当的序列化方式可以确保数据正确无误地被存储和读取,提升系统的稳定性和维护性,避免由于默认序列化带来的乱码或不兼容问题,从而保障应用的高效运行和数据的安全完整。

目录

序列化介绍

问题解析

问题测试

解决方案

方案一

方案二


序列化介绍

序列化 是指将对象的状态信息转换为可以存储或传输的形式的过程。在反序列化时,这个过程是相反的,即将这些信息还原成对象。

当你将数据存储到Redis中时,如果发现数据变成字节,这通常与序列化方式有关。指在Java环境中使用Redis客户端,默认情况下会使用JDK内置的序列化方式(即**Serializable** 接口及**ObjectOutputStream**等类来实现对象的序列化)。

问题解析

兼容性问题:JDK序列化格式是Java特有的,这意味着只有Java程序才能反序列化这些对象。如果你的系统中有非Java组件需要访问Redis中的数据,那么它们将无法直接读取这些序列化的对象。

性能问题:JDK序列化机制有时会比较慢,并且生成的序列化内容可能比其他序列化方法(如JSON, Protobuf, Avro等)更大,从而影响网络传输效率和存储空间。

安全性考虑:反序列化不受信任的数据源可能导致安全漏洞,例如反序列化攻击。这是因为反序列化过程会执行某些代码,如果攻击者能够控制输入流,就可能利用这一点执行恶意代码.

其实可读性也非常差(这谁能看出来name=小明, age=18是上面这一大串)

问题测试

使用SpringDataRedis客户端:

创建一个测试的SpringBoot项目,引入依赖:

java 复制代码
        <!--redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

在application.yaml加入:

java 复制代码
spring:
  data:
    redis:
      host: localhost
      port: 6379
      password:
      lettuce:
        pool:
          max-active: 8
          min-idle: 0
          max-idle: 8
          max-wait: 1000

在测试类,加入以下代码:

复制代码
@SpringBootTest
class SpringDataRedisDemoApplicationTests {

    @Autowired
    private RedisTemplate redisTemplate;
    @Test
    void testString() {
        redisTemplate.opsForValue().set("time","12");
        Object time = redisTemplate.opsForValue().get("time");
        System.out.println("time = " + time);
    }


    @Test
    void testUser() {
        redisTemplate.opsForValue().set("user",new User("小明",18));
        User user = (User) redisTemplate.opsForValue().get("user");
        System.out.println("user = " + user);
    }
}

运行后查看Java客户端工具:

解决方案

方案一

配置**RedisTemplate,**使用JSON作为序列化格式,实现自动序列化和反序列化。

加入下列代码,设置特定的序列化工具(GenericJackson2JsonRedisSerializer

java 复制代码
@Configuration
public class RedisConfig {
    /**
     * RedisTemplate配置序列化规则
     * @param connectionFactory
     * @return
     */
    @Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        // 创建RedisTemplate对象
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        // 设置连接工厂
        redisTemplate.setConnectionFactory(connectionFactory);
        // 创建Json序列化工具
        GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
        // 设置key的序列化规则
        redisTemplate.setKeySerializer(RedisSerializer.string());
        redisTemplate.setHashKeySerializer(RedisSerializer.string());
        // 设置value的序列化规则
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        return redisTemplate;
    }
}

修改测试类注入的RedisTemplate类型

java 复制代码
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

运行结果如下:

可以看到可读性大大提高,可以确保所有存储到Redis中的数据都以一种一致且易于理解的方式进行序列化和反序列化,提升了与Redis交互时的序列化效率、数据兼容性和易用性,使得存储和检索过程更加高效和直观。

方案二

方案一有一个缺点,在储存对象时,把类的class类型写入了JSON结果中,存入Redis,带来了额外的内存开销。(在大量数据的情况下可能给内存带来压力)

使用StringRedisTemplate,手动实现序列化和反序列化。

java 复制代码
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    
    private static final ObjectMapper mapper = new ObjectMapper();
    
    @Test
    void testUser() throws JsonProcessingException {
        //创建对象
        User user = new User("张三", 18);
        // 手动序列化
        String json = mapper.writeValueAsString(user);
        // 存入redis
        stringRedisTemplate.opsForValue().set("users",json);
        // 取出数据
        String users = stringRedisTemplate.opsForValue().get("users");
        // 手动反序列化
        User user1 = mapper.readValue(users, User.class);
        // 输出
        System.out.println("user1 = " + user1);
    }

实现效果如下:

实现了去除类的class类型,节省了内存。

相关推荐
pqq的迷弟4 分钟前
redis多路复用IO模型 以及 6.0引入的多线程模型
数据库·redis·php
?abc!15 分钟前
缓存(1):三级缓存
缓存
larance32 分钟前
Django rest_framework 信号机制生成并使用token
数据库·django·sqlite
悻运33 分钟前
Spark缓存
大数据·缓存·spark
didiplus1 小时前
MySQL 8.0 OCP(1Z0-908)英文题库(11-20)
数据库·mysql·adb·认证·ocp
等雨季2 小时前
电商双11美妆数据分析(二)
数据库
Web极客码2 小时前
如何修复WordPress数据库
服务器·数据库·wordpress
火龙谷2 小时前
【hadoop】Sqoop数据迁移工具的安装部署
数据库·hadoop·sqoop
JhonKI3 小时前
【MySQL】存储引擎 - MyISAM详解
数据库·mysql
ikun·3 小时前
MySQL 数据库
数据库·mysql