聊聊RedisTemplate的各种序列化器

[版权申明] 非商业目的注明出处可自由转载
出自:shusheng007

文章目录

  • 概述
  • 序列化器
    • 作用和原理
    • JDK 序列化方式
      • 多一点
    • String 序列化方式
    • JSON 序列化方式
  • 总结
  • 源码

概述

在SpringBoot中使用redis基本上都是通过Spring Data Redis,那就不得不说RedisTemplate了。在我刚接触它的时候比较懵逼的就是给其设置各种序列化器了,今天我们来唠唠他们。

序列化器

众所周知,使用RedisTemplate可以对Redis的各种数据结构进行操作,如下图所示。

在这里插入图片描述

作用和原理

那我们为什么需要序列化器呢,这是个啥玩意儿?

现在闭目思考一下我们是如何使用redis的?是不是先将数据存储在redis上,然后用的时候再读取出来?

那我们存储在redis里的内容是啥呢?有时是字符串,例如"ShuSheng007",大部分时间是对象,例如StudentList<Student>Map<String,Student>等等。这些个对象肯定是不能直接存储到redis上的,我们需要想办法先把它们转成byte[]后才能存储到redis上,这就是所谓的序列化。等用的时候还的把byte[]转化为相应的对象,这就是所谓的反序列化。序列化器就是完成这两个功能的。

下面是Spring中Redis序列化器的接口,从源码中可以非常清晰的看到它就干了这两个事情。

public interface RedisSerializer<T> {@Nullablebyte[] serialize(@Nullable T t) throws SerializationException;@NullableT deserialize(@Nullable byte[] bytes) throws SerializationException;
}

之所以存在这么多序列化器,是因为我们可以通过各种方式将对象转为byte[],也就是这个接口可以有各种实现类。总结一下,大概有如下几种:

  • JDK 序列化方式 (默认)
  • String 序列化方式
  • JSON 序列化方式
  • XML 序列化方式

其中XML序列化器不怎么用,我们就忽略它吧。

在讲解各种序列化器之前我们应该先搞清楚RedisTemplate都有哪些地方需要设置序列化器。

public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V>, BeanClassLoaderAware {@SuppressWarnings("rawtypes") private @Nullable RedisSerializer keySerializer = null;@SuppressWarnings("rawtypes") private @Nullable RedisSerializer valueSerializer = null;@SuppressWarnings("rawtypes") private @Nullable RedisSerializer hashKeySerializer = null;@SuppressWarnings("rawtypes") private @Nullable RedisSerializer hashValueSerializer = null;}

从上面的源码可以发现总共有四个地方需要设置序列化器。这个和Redis提供的数据结构有关,所以我们在往redis里面存放数据的时候有两种方式。一种是key/value形式,另一种就是 key/hashMap, 那个hashMap又是key/value形式, 所以一共有四个地方用到序列化器。

key和hashKey一般都使用String序列化方式,有变化的一般是value和hashValue。

JDK 序列化方式

JdkSerializationRedisSerializer完成,它是默认序列化器,如果不手动设置就会使用它。它是利用Java自身提供的序列化方案来工作的,也就是说你要存放到redis中的数据必须是可序列化的,例如实现了Serializable接口。

我们来实践一下,使用下面的代码就给RedisTemplate的value设置JdkSerializationRedisSerializer

template.setKeySerializer(RedisSerializer.string());
template.setValueSerializer(RedisSerializer.java());

我们有如下一个类

public class KeyValue implements Serializable {private String key;private Object value;...
}

将其保存到redis中

public void testRedisSerializer() {ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();valueOperations.set("object",new KeyValue("age",18));
}

查看结果,你会发现value是人类不可读的样子

\xac\xed\x00\x05sr\x00.top.shusheng007.redisintegrate.domain.KeyValue\xb2\xf9\xec\xa5\xb5\x89\xb99\x02\x00\x02L\x00\x03keyt\x00\x12Ljava/lang/String;L\x00\x05valuet\x00\x12Ljava/lang/Object;xpt\x00\x03agesr\x00\x11java.lang.Integer...

正是因为这个原因,外加跨平台问题导致其在生产中用的也比较少。

多一点

如果在创建JdkSerializationRedisSerializer时传入一个ClassLoader,如果这个类加载器和你使用类的加载器是同一个的话,查询出的值可以直接转成对应的类型对象的。

//传入当前配置类的ClassLoader
template.setValueSerializer(RedisSerializer.java(getClass().getClassLoader()));valueOperations.set("object",new KeyValue("age",18));
//从redis获取的值可以直接强转
KeyValue keyValue = (KeyValue) valueOperations.get("object");

String 序列化方式

StringRedisSerializer完成,这个应该没什么可说的。一般情况下,key和hashKey都使用这个序列化器,它们两一般也就存放字符串。value和hashValue一般都不会设置为它,Spring Data Redis 单独提供了一个操作字符串的StringRedisTemplate

public class StringRedisTemplate extends RedisTemplate<String, String> {...
}

JSON 序列化方式

GenericJackson2JsonRedisSerializer或者Jackson2JsonRedisSerializer完成。我们一般将value和hashValue的序列化器设置为其中一个,用来以json的形式保存数据。那这两个有什么区别呢?

  • Jackson2JsonRedisSerializer

设置序列化器

Jackson2JsonRedisSerializer<Object> valuesSerializer2 = new Jackson2JsonRedisSerializer(Object.class);
template.setValueSerializer(valuesSerializer2);

使用

 valueOperations.set("object",new KeyValue("age",18));Object keyValue =  valueOperations.get("object");String clsName = keyValue.getClass().getCanonicalName();log.info("object:{},name:{}", keyValue,clsName);

查看redis中value值,可见就是普通json格式

{"key": "age","value": 18
}

其中那个keyValue是一个java.util.LinkedHashMap类型,这个是java自动解析的类型。所以如果我们要将其解析成对应的类型的话就要借助与Jackson了。

 ObjectMapper objectMapper = new ObjectMapper();KeyValue keyValue = objectMapper.convertValue(keyValue, KeyValue.class);
  • GenericJackson2JsonRedisSerializer

这个与Jackson2JsonRedisSerializer的区别是生成的json里携带了类信息,反序列化为同一个类的时候不需要借助于Jackson。但这也会产生新的问题,例如一个服务向redis里写数据,另一个服务取数据,但是他们的类信息不一样就无法反序列化了。

设置序列化器

Jackson2JsonRedisSerializer<Object> valuesSerializer2 = new Jackson2JsonRedisSerializer(Object.class);
template.setValueSerializer(valueSerializer);

使用,注意我们在反序列化的时候直接进行了强转。

 valueOperations.set("object",new KeyValue("age",18));KeyValue keyValue = (KeyValue) valueOperations.get("object");String clsName = keyValue.getClass().getCanonicalName();log.info("object:{},name:{}", keyValue,clsName);

查看redis中value值,可见多了一个@class信息,是在反序列时提供类型信息的。

{"@class": "top.shusheng007.redisintegrate.domain.KeyValue","key": "age","value": 18
}

总结

通常key/hashKey使用字符串序列化器,value/hashValue使用Json序列化器。当服务自己存自己取的话使用GenericJackson2JsonRedisSerializer,但是如果取其他服务存储的Json值就要使用Jackson2JsonRedisSerializer

以上就是RedisRemplate的几个序列化器的总结。是不是感觉也没那么难了?小白面前的大山就是老鸟眼中的土坷垃。你回头看看你的经历,是不是很多当时感觉非常艰难的事情在你攻克他们后感觉也没那么难,而且还会感慨一句:这也没多难,为什么我当时就是不会呢?人生也是一样,当你回顾你的一生时大多遗憾的事情都是没有做的事情…

源码

一如既往,你可以从首发找到源码 redis-integration

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/67152.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

11 个 Python 编码习惯

让你成为糟糕程序员的 11 个 Python 编码习惯 简介 Python 因其简洁性和可读性而备受推崇&#xff0c;但即使是最有经验的程序员也可能会陷入影响代码质量的习惯中。 在本博客中&#xff0c;我们将探讨 10 种常见的编码习惯&#xff0c;它们会降低您作为 Python 程序员的效率。…

2023年国赛数学建模思路 - 复盘:校园消费行为分析

文章目录 0 赛题思路1 赛题背景2 分析目标3 数据说明4 数据预处理5 数据分析5.1 食堂就餐行为分析5.2 学生消费行为分析 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 赛题背景 校园一卡通是集…

Intel汇编和ATT汇编的区别?

一、前缀不同 在 Intel 语法中&#xff0c;没有寄存器前缀或立即前缀。 然而&#xff0c;在 AT&T 中&#xff0c;寄存器的前缀是“%”&#xff0c;而 immed 的前缀是“$”。 Intel 语法十六进制或二进制即时数据分别带有“h”和“b”后缀。 此外&#xff0c;如果第一个十六…

算法通关村第七关——递归和迭代实现二叉树前中后序遍历

1.递归 1.1 熟悉递归 所有的递归有两个基本特征&#xff1a; 执行时范围不断缩小&#xff0c;这样才能触底反弹。终止判断在调用递归的前面。 写递归的步骤&#xff1a; 从小到大递推。分情况讨论&#xff0c;明确结束条件。组合出完整方法。想验证就从大到小画图推演。 …

使用AffNet和HardNet进行图像匹配

一、说明 我们有一个任务是找到与给定查询图像最匹配的图像。首先&#xff0c;我们在OpenCV中尝试了使用SIFT描述符和基于Flann的匹配器的经典图像匹配。结果是完全错误的。然后是词袋...最后&#xff0c;找到了AffNet和HardNet。 二、关于AffNet和HardNet 本文专门介绍如何进…

【枚举倍数+容斥】CF803 F

Problem - F - Codeforces 题意&#xff1a; 思路&#xff1a; 正难则反&#xff0c;考虑容斥 即考虑gcd ! 1的所有子序列个数 因为子序列内部无序&#xff0c;因此不算真正的子序列&#xff0c;考虑枚举倍数 根据经典套路&#xff0c;我们去枚举 gcd&#xff0c;然后去枚…

win10下如何安装ffmpeg

安装ffmpeg之前先安装win10 绿色软件管理软件&#xff1a;scoop. Scoop的基本介绍 Scoop是一款适用于Windows平台的命令行软件&#xff08;包&#xff09;管理工具&#xff0c;这里是Github介绍页。简单来说&#xff0c;就是可以通过命令行工具&#xff08;PowerShell、CMD等…

Pytorch安装教程:最新保姆级教程

目录 概述 重要的事情说三遍&#xff1a;不需要装cuda、不需要装cuda、不需要装cuda 1.查看自己NVIDIA版本 2.创建一个conda 环境 3.安装pytorch 本文意在帮助即将步入深入学习领域的学子 在这之前首先你需要安装好anaconda&#xff0c;不懂的可以下面这篇文章 最新Anaco…

C语言的动态分配空间C++的动态分配空间问题

动态分配空间 C&#xff1a;1、malloc 2、calloc C&#xff1a;new运算符 一 malloc malloc()&#xff1a; 这个函数用于分配一块指定大小的内存块&#xff0c;并返回一个指向该内存块的指针。语法如下&#xff1a; void* malloc(size_t size); 示例&#xff1a; int* ptr …

【软件测试】我的2023面试经验谈

最近行业里有个苦涩的笑话&#xff1a;公司扛过了之前的三年&#xff0c;没扛过摘下最近的一年&#xff0c;真是让人想笑又笑不出来。年前听说政策的变化&#xff0c;大家都满怀希望觉得年后行情一片大好&#xff0c;工作岗位激增&#xff0c;至少能有更多的机会拥抱未来。然而…

nodejs+vue+elementui美食网站的设计与实现演示录像2023_0fh04

本次的毕业设计主要就是设计并开发一个美食网站软件。运用当前Google提供的nodejs 框架来实现对美食信息查询功能。当然使用的数据库是mysql。系统主要包括个人信息修改&#xff0c;对餐厅管理、用户管理、餐厅信息管理、菜系分类管理、美食信息管理、美食文化管理、系统管理、…

android app控制ros机器人五(百度地图)

半吊子改安卓&#xff0c;新增了标签页&#xff0c;此标签页需要显示百度地图 按照官方教程注册信息&#xff0c;得到访问应用AK&#xff0c;步骤也可以参照下面csdn Android地图SDK | 百度地图API SDK 【Android】实现百度地图显示_宾有为的博客-CSDN博客 本人使用的是aar开…