【小家Spring】Redis序列化、RedisTemplate序列化方式大解读,介绍Genericjackson2jsonredisserializer序列化器的坑(上)

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 【小家Spring】Redis序列化、RedisTemplate序列化方式大解读,介绍Genericjackson2jsonredisserializer序列化器的坑(上)

前言


上一篇已经介绍了优雅的操作Redis:

【小家Spring】Spring Boot中使用RedisTemplate优雅的操作Redis,并且解决RedisTemplate泛型注入的问题。本篇着重介绍一下几种常用的序列化方式


最近在做一个项目,由于并发量大,大量使用到了RedisTemplate来操作Redis。但使用过程中,遇到了不少的坑,各种翻看源码来跟踪,也总结出了不少的经验。


因此今天专门做一篇专文来记录这些坑,也具体说说RedisTemplate的各种序列化方式的差异性。希望对大家也能有所帮助,帮助大家解决一些疑惑


1.序列化问题


    RedisTemplate在遇到复杂类型的返序列化时,即使加了泛型,获取到的时机类型为LinedHashMap,需要得到结果后再次返序列化,不然会报类型转换异常。

如下:这样处理才是安全的:

image.png


在执行序列化的时候,操作的如果是Bean,必须有默认构造器,否则报错


2.redis集群问题(关于集群的这几个问题,后续在专门演示和解释)


如果连接的为Redis集群,则不能用管道的方法,除非改写管道的类


模糊查询的时候需要获取到所有的node信息,依次查询


Spring提供的序列化方式


从源码里看:


image.png


我们可以很清晰的看到,Spring为我们提供了6种不同的序列化方式。


特别说明一下:如果你是在Spring Boot1.5.x环境下使用,你可能看到是9种实现或者是7种实现,如下图所示


image.png


解释:


关于前面两个,并非Spring官方提供,而是由alibaba的FastJson自己实现的。我们看看FastJson的包结构,发现它很友好的提供了一些常用的转化器


image.png


因此此处暂时不做过多描述,后面再说。


另外还有一个JacksonJsonRedisSerializer类,被标记为过期。而这个类在SpringBoot2.0就直接被移除掉了,因此以后的版本不用理会了。


下面主要介绍一下,Spring官方现在还存在的6大序列化器:


Generic单词意思:一般的; 通用的;类的,属性的;


1.OxmSerializer

以xml格式存储(但还是String类型~),解析起来也比较复杂,效率也比较低。因此几乎没有人再使用此方式了


2.JdkSerializationRedisSerializer

从源码里可以看出,这是RestTemplate类默认的序列化方式。若你没有自定义,那就是它了。


  @Override
  public void afterPropertiesSet() {
    super.afterPropertiesSet();
    boolean defaultUsed = false;
    if (defaultSerializer == null) {
      defaultSerializer = new JdkSerializationRedisSerializer(
          classLoader != null ? classLoader : this.getClass().getClassLoader());
    }
    ...


使用JDK自带的序列化方式,有明显的缺点:

首先它要求存储的对象都必须实现java.io.Serializable接口,比较笨重

其次,他存储的为二进制数据,这对开发者是不友好的

再次,因为他存储的为二进制。但是有时候,我们的Redis会在一个项目的多个project中共用,这样如果同一个可以缓存的对象在不同的project中要使用两个不同的key来分别缓存,既麻烦,又浪费。


使用JDK提供的序列化功能。 优点是反序列化时不需要提供(传入)类型信息(class),但缺点是需要实现Serializable接口,还有序列化后的结果非常庞大,是JSON格式的5倍左右,这样就会消耗redis服务器的大量内存。

    @Autowired
    private RedisTemplate redisTemplate;
    @Test
    public void contextLoads() {
        ValueOperations<String, Person> valueOperations = redisTemplate.opsForValue();
        valueOperations.set("aaa", new Person("fsx", 24));
        Person p = valueOperations.get("aaa"); //Person(name=fsx, age=24)
        System.out.println(p);
    }


存储的为二进制,根本开不出来是什么,对开发者调试也很不友好



image.png


    3.StringRedisSerializer

也是StringRedisTemplate默认的序列化方式,key和value都会采用此方式进行序列化,是被推荐使用的,对开发者友好,轻量级,效率也比较高。

(例子略)


    4.GenericToStringSerializer

他需要调用者给传一个对象到字符串互转的Converter(相当于转换为字符串的操作交给转换器去做),个人觉得使用起来其比较麻烦,还不如直接用字符串呢。所以不太推荐使用


后面两种序列化方式是重点


    5.Jackson2JsonRedisSerializer

从名字可以看出来,这是把一个对象以Json的形式存储,效率高且对调用者友好


优点是速度快,序列化后的字符串短小精悍,不需要实现Serializable接口。

但缺点也非常致命:那就是此类的构造函数中有一个类型参数,必须提供要序列化对象的类型信息(.class对象)。 通过查看源代码,发现其在反序列化过程中用到了类型信息(必须根据此类型信息完成反序列化)。


   6.GenericJackson2JsonRedisSerializer

基本和上面的Jackson2JsonRedisSerializer功能差不多,使用方式也差不多,**但是是推荐使用的**

需要注意:(使用区别)


    @Test
    public void contextLoads() {
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());
        //ValueOperations<String, String> valueOperations = stringRedisTemplate.opsForValue();
        //此处泛型 因为编译器无法校验  所以如果value序列化方式是字符串 下面就会报错了
        ValueOperations<String, Person> valueOperations = redisTemplate.opsForValue();
        valueOperations.set("key", new Person("fsx", 24)); //java.lang.ClassCastException: com.fsx.run2.bean.Person cannot be cast to java.lang.String
        Person value = valueOperations.get("key");
        System.out.println(value);
    }


如上,假如我value的序列化方式设置为String序列化器。但是set值的时候放对象了。这个时候就直接报错了,并不会自动调用toString()方法,此处一定要注意。还需要特别是初始化RestTemplate的时候,value的序列化方式禁止使用有类型偏向的StringRedisSerializer。若有需要,你直接使用StringRedisTemplate操作即可

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
4月前
|
JSON NoSQL Java
redis的java客户端的使用(Jedis、SpringDataRedis、SpringBoot整合redis、redisTemplate序列化及stringRedisTemplate序列化)
这篇文章介绍了在Java中使用Redis客户端的几种方法,包括Jedis、SpringDataRedis和SpringBoot整合Redis的操作。文章详细解释了Jedis的基本使用步骤,Jedis连接池的创建和使用,以及在SpringBoot项目中如何配置和使用RedisTemplate和StringRedisTemplate。此外,还探讨了RedisTemplate序列化的两种实践方案,包括默认的JDK序列化和自定义的JSON序列化,以及StringRedisTemplate的使用,它要求键和值都必须是String类型。
redis的java客户端的使用(Jedis、SpringDataRedis、SpringBoot整合redis、redisTemplate序列化及stringRedisTemplate序列化)
|
8月前
|
NoSQL 测试技术 Go
【Golang】国密SM2公钥私钥序列化到redis中并加密解密实战_sm2反编(1)
【Golang】国密SM2公钥私钥序列化到redis中并加密解密实战_sm2反编(1)
|
3月前
|
JSON 缓存 NoSQL
Redis 在线查看序列化对象技术详解
Redis 在线查看序列化对象技术详解
55 2
|
4月前
|
JSON 缓存 NoSQL
redis序列化数据时,如何包含clsss类型信息?
通过配置 `com.fasterxml.jackson.databind.ObjectMapper` 的 `enableDefaultTyping` 方法,可以使序列化后的 JSON 包含类信息。
66 2
|
6月前
RedisTemplate序列化的问题
RedisTemplate序列化的问题
55 1
|
7月前
|
NoSQL Redis
redis使用jackson序列化数据配置文件
redis使用jackson序列化数据配置文件
130 5
|
6月前
|
JSON NoSQL Java
Redis18的Java客户端-StringRedisTemplate,序列化存在的问题,使用StringRedisTemplate解决序列化的方法
Redis18的Java客户端-StringRedisTemplate,序列化存在的问题,使用StringRedisTemplate解决序列化的方法
|
1天前
|
XML Java 应用服务中间件
Spring Boot 两种部署到服务器的方式
本文介绍了Spring Boot项目的两种部署方式:jar包和war包。Jar包方式使用内置Tomcat,只需配置JDK 1.8及以上环境,通过`nohup java -jar`命令后台运行,并开放服务器端口即可访问。War包则需将项目打包后放入外部Tomcat的webapps目录,修改启动类继承`SpringBootServletInitializer`并调整pom.xml中的打包类型为war,最后启动Tomcat访问应用。两者各有优劣,jar包更简单便捷,而war包适合传统部署场景。需要注意的是,war包部署时,内置Tomcat的端口配置不会生效。
56 17
Spring Boot 两种部署到服务器的方式
|
1天前
|
Dart 前端开发 JavaScript
springboot自动配置原理
Spring Boot 自动配置原理:通过 `@EnableAutoConfiguration` 开启自动配置,扫描 `META-INF/spring.factories` 下的配置类,省去手动编写配置文件。使用 `@ConditionalXXX` 注解判断配置类是否生效,导入对应的 starter 后自动配置生效。通过 `@EnableConfigurationProperties` 加载配置属性,默认值与配置文件中的值结合使用。总结来说,Spring Boot 通过这些机制简化了开发配置流程,提升了开发效率。
29 17
springboot自动配置原理
|
6天前
|
XML JavaScript Java
SpringBoot集成Shiro权限+Jwt认证
本文主要描述如何快速基于SpringBoot 2.5.X版本集成Shiro+JWT框架,让大家快速实现无状态登陆和接口权限认证主体框架,具体业务细节未实现,大家按照实际项目补充。
43 11