可以看到4个序列化干系的属性 ,紧张是用于KEY和VALUE的序列化,比如说我们常常会将POJO工具存储到Redis中,一样平常情形下会利用JSON办法序列化成字符串存储到Redis中 。

Spring供应的Redis数据构造的操作类

ValueOperations 类,供应 Redis String API 操作ListOperations 类,供应 Redis List API 操作SetOperations 类,供应 Redis Set API 操作ZSetOperations 类,供应 Redis ZSet(Sorted Set) API 操作GeoOperations 类,供应 Redis Geo API 操作HyperLogLogOperations 类,供应 Redis HyperLogLog API 操作StringRedisTemplate

RedisTemplate支持泛型,StringRedisTemplate K/V 均为String类型。

phpredis序列化Redis之RedisTemplate的序列化方法深刻解读 PHP

org.springframework.data.redis.core.StringRedisTemplate 继续RedisTemplate类,利用 org.springframework.data.redis.serializer.StringRedisSerializer字符串序列化办法。

RedisSerializer序列化接口

RedisSerializer接口是Redis序列化接口,用于Redis KEY和VALUE的序列化。

RedisSerializer接口的实现类如下:

默认Redis供应了11中的序列化办法,归类一下紧张分为:

JDK序列化办法(默认)String序列化办法JSON序列化办法XML序列化办法JDK序列化办法(默认)

org.springframework.data.redis.serializer.JdkSerializationRedisSerializer,默认不配置的情形RedisTemplate采取的是该数据序列化办法,可以查看一下源码:

Spring Boot自动化配置RedisTemplate Bean工具时,就未设置默认的序列化办法。
绝大多数情形下,并不推举利用JdkSerializationRedisSerializer进行序列化。
紧张是未便利人工排查数据。
我们来做个测试:

运行单元测试:

创造key跟value的值都是16进制字符串,可以看到key跟value实际上保存的都因此byte[]字节数组的格式存储:

key被序列化成这样,线上通过key去查询对应的value非常未便利,以是key肯定是不能被这样序列化的。
value被序列化成这样,除了阅读可能困难一点,不支持跨措辞外,实际上也没多大问题。
不过,实际线上场景,还是利用JSON序列化居多。

String序列化办法

org.springframework.data.redis.serializer.StringRedisSerializer,字符串和二进制数组都直接转换:

默认的话,StringRedisTemplate的key和value采取的便是这种序列化方案。

JSON序列话办法

GenericJackson2JsonRedisSerializer

org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer 利用Jackson 实现JSON的序列化办法,Generic单词翻译过来表示:通用的意思,可以看出,是支持所有类。

RedisConfig配置

通过配置办法选择对应Redis数据的序列化办法,配置如下:

package com.example.jedisserializefrombytestojson.config;import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer;import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer;import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.data.redis.connection.RedisConnectionFactory;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;import org.springframework.data.redis.serializer.RedisSerializer;import org.springframework.data.redis.serializer.StringRedisSerializer;/ Redis配置 @author: jacklin @date: 2022/9/9 0:07 /@Configurationpublic class RedisConfig { //GenericJackson2JsonRedisSerializer @Bean @ConditionalOnMissingBean(name = &#34;redisTemplate") public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory){ RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(factory); //String的序列化办法 StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // 利用GenericJackson2JsonRedisSerializer 更换默认序列化(默认采取的是JDK序列化) GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); //key序列化办法采取String类型 template.setKeySerializer(stringRedisSerializer); //value序列化办法采取jackson类型 template.setValueSerializer(genericJackson2JsonRedisSerializer); //hash的key序列化办法也是采取String类型 template.setHashKeySerializer(stringRedisSerializer); //hash的value也是采取jackson类型 template.setHashValueSerializer(genericJackson2JsonRedisSerializer); template.afterPropertiesSet(); return template; } ////Jackson2JsonRedisSerializer //@Bean //@ConditionalOnMissingBean(name = "redisTemplate") //public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { // RedisTemplate<String, Object> template = new RedisTemplate<>(); // template.setConnectionFactory(factory); // // //String的序列化办法 // StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // // 利用Jackson2JsonRedisSerialize 更换默认序列化(默认采取的是JDK序列化) // Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class); // // //key序列化办法采取String类型 // template.setKeySerializer(stringRedisSerializer); // //value序列化办法采取jackson类型 // template.setValueSerializer(jackson2JsonRedisSerializer); // //hash的key序列化办法也是采取String类型 // template.setHashKeySerializer(stringRedisSerializer); // //hash的value也是采取jackson类型 // template.setHashValueSerializer(jackson2JsonRedisSerializer); // template.afterPropertiesSet(); // return template; //} // ////FastJsonRedisSerializer //@Bean("redisTemplate") //public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory){ // RedisTemplate<String, Object> template = new RedisTemplate<>(); // template.setConnectionFactory(factory); // // //String序列化办法 // StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // // 利用FastJsonRedisSerializer更换默认序列化(默认采取的是JDK序列化) // FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class); // // //key序列化办法采取String类型 // template.setKeySerializer(stringRedisSerializer); // //value序列化办法采取jackson类型 // template.setValueSerializer(fastJsonRedisSerializer); // //hash的key序列化办法也是采取String类型 // template.setHashKeySerializer(stringRedisSerializer); // //hash的value也是采取jackson类型 // template.setHashValueSerializer(fastJsonRedisSerializer); // template.afterPropertiesSet(); // return template; //}}复制代码

运行以下测试类:

@Testvoid redisTemplateSerializeTest() { String redisTemplateStringKey = "redisTemplateStringKey"; String redisTemplateUserObjectKey = "redisTemplateUserObjectKey"; String redisTemplateUserArrayObjectKey = "redisTemplateUserArrayObjectKey"; String redisTemplateJSONObjectKey = "redisTemplateJSONObjectKey"; String redisTemplateJSONArrayKey = "redisTemplateJSONArrayKey"; //序列化String类型和反序列化String类型 redisTemplate.opsForValue().set(redisTemplateStringKey, "austin"); String austin = (String) redisTemplate.opsForValue().get(redisTemplateStringKey); System.out.println("stringGet: " + austin); //序列化Object工具类型和反序列化Object工具类型 (User工具) User user = new User("123", "austin", 25); redisTemplate.opsForValue().set(redisTemplateUserObjectKey, user); User userGet = (User) redisTemplate.opsForValue().get(redisTemplateUserObjectKey); System.out.println("userGet: " + userGet); //序列化Object工具数组类型和反序列化Object工具数组类型 (User[]工具数组) User user1 = new User("1", "austin1", 25); User user2 = new User("2", "austin2", 25); User[] userArray = new User[]{user1, user2}; redisTemplate.opsForValue().set(redisTemplateUserArrayObjectKey, userArray); User[] userArrayGet = (User[]) redisTemplate.opsForValue().get(redisTemplateUserArrayObjectKey); System.out.println("userArrayGet: " + userArrayGet); //序列化JSONObject工具类型和反序列化JSONObject工具类型 JSONObject jsonObject = new JSONObject(); jsonObject.put("id", "123"); jsonObject.put("name", "austin"); jsonObject.put("age", 25); redisTemplate.opsForValue().set(redisTemplateJSONObjectKey, jsonObject); JSONObject jsonObjectGet = (JSONObject) redisTemplate.opsForValue().get(redisTemplateJSONObjectKey); System.out.println("jsonObjectGet: " + jsonObjectGet); //序列化JSONArray工具类型和反序列化JSONArray工具类型 JSONArray jsonArray = new JSONArray(); JSONObject jsonObject1 = new JSONObject(); jsonObject1.put("id", "1"); jsonObject1.put("name", "austin1"); jsonObject1.put("age", 25); JSONObject jsonObject2 = new JSONObject(); jsonObject2.put("id", "1"); jsonObject2.put("name", "austin2"); jsonObject2.put("age", 25); jsonArray.add(jsonObject1); jsonArray.add(jsonObject2); redisTemplate.opsForValue().set(redisTemplateJSONArrayKey, jsonArray); JSONArray jsonArrayGet = (JSONArray) redisTemplate.opsForValue().get(redisTemplateJSONArrayKey); System.out.println("jsonArrayGet: " + jsonArrayGet);}复制代码

不雅观察redis数据的存储格式:

key- value :

字符串类型

Key: redisTemplateStringKeyValue: "austin"复制代码工具类型

Key: redisTemplateUserObjectKeyValue:{ "@class": "com.example.jedisserializefrombytestojson.User", "id": "123", "name": "austin", "age": 25}复制代码工具数组类型

Key: redisTemplateUserArrayObjectKeyValue: [ "[Lcom.example.jedisserializefrombytestojson.User;", [ { "@class": "com.example.jedisserializefrombytestojson.User", "id": "1", "name": "austin1", "age": 25 }, { "@class": "com.example.jedisserializefrombytestojson.User", "id": "2", "name": "austin2", "age": 25 } ]]复制代码JSONObject类型

Key: redisTemplateJSONObjectKeyValue:{ "@class": "com.alibaba.fastjson.JSONObject", "name": "austin", "id": "123", "age": 25}复制代码JSONArray类型

Key: redisTemplateJSONArrayKeyValue: [ "com.alibaba.fastjson.JSONArray", [ { "@class": "com.alibaba.fastjson.JSONObject", "name": "austin1", "id": "1", "age": 25 }, { "@class": "com.alibaba.fastjson.JSONObject", "name": "austin2", "id": "1", "age": 25 } ]]复制代码

运行redisTemplateSerializeTest测试类,结果创造该办法序列化和反序列化都没有问题,果真是通用性序列化办法:

我们来思考下,在将一个工具序列化成一个字符串,怎么担保字符串反序列化成工具的类型呢?Jackson通过 Default Typing,会在字符串多冗余一个类型,这样反序列化就知道详细的类型了。

从结果创造,利用GenericJackson2JsonRedisSerializer序列化办法,String类型、工具、工具数组、JSONObject、JSONArray序列化和反序列化都没有问题,value值序列化后多了@class属性,反序列化的工具的类型就可以从这里获取到。
@class属性完美办理了反序列化后的工具类型,以是实际项目中,目前很多采取 GenericJackson2JsonRedisSerializer序列化办法。

Jackson2JsonRedisSerializer

org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer

不雅观察redis数据的存储格式:

key- value:

字符串类型

Key: redisTemplateStringKeyValue: "austin"复制代码工具类型

Key: redisTemplateUserObjectKeyValue:{ "id": "123", "name": "austin", "age": 25}复制代码

与上面GenericJackson2JsonRedisSerializer序列化办法结果不同的是,value没有@class属性。

工具数组类型

Key: redisTemplateUserArrayObjectKeyValue: [ { "id": "1", "name": "austin1", "age": 25 }, { "id": "2", "name": "austin2", "age": 25 }]复制代码

与上面GenericJackson2JsonRedisSerializer序列化办法结果不同的是,value没有"@class": "com.example.jedisserializefrombytestojson.User" 工具类型属性。

JSONObject类型

Key: redisTemplateJSONObjectKeyValue:{ "name": "austin", "id": "123", "age": 25}复制代码

与上面GenericJackson2JsonRedisSerializer序列化办法结果不同的是,value没有"@class": "com.alibaba.fastjson.JSONObject"属性。

JSONArray类型

Key: redisTemplateJSONArrayKeyValue: [ { "name": "austin1", "id": "1", "age": 25 }, { "name": "austin2", "id": "1", "age": 25 }]复制代码

与上面GenericJackson2JsonRedisSerializer序列化办法结果不同的是,value没有 "com.alibaba.fastjson.JSONArray" 工具类型属性。

Jackson2JsonRedisSerializer与GenericJackson2JsonRedisSerializer序列化结果不同的是,前者并没有@class或者@type类型属性,这种序列化办法可能会导致获取redis数据反序列化成POJO工具时候出错,导致反序列化失落败,以是一样平常也很少利用该办法。

比如在工具逼迫转换的情形,会报错:

报错信息很明显,不能直接将JSONObject工具逼迫转换成User工具,不能通过办法获取转换:

//该办法强转会报错User userGet = (User) redisTemplate.opsForValue().get(redisTemplateUserObjectKey);复制代码

而精确的办法该当是:

//通过com.fastxml.jackson的ObjectMapper工具进行转换Object userObject = redisTemplate.opsForValue().get(redisTemplateUserObjectKey);ObjectMapper objectMapper = new ObjectMapper();User userGet = objectMapper.convertValue(userObject, User.class);System.out.println("userGet: " + userGet);复制代码

这也是redis序列化和反序列化紧张非常把稳地方。

总结

采取GenericJackson2JsonRedisSerializer序列化办法对付String、工具、工具数组、JSONObject、JSONArray的序列化反序列化操作都正常,工具强转是没有任何问题,但是采取Jackson2JsonRedisSerializer序列化办法在工具逼迫时,也便是利用 User userGet = (User) redisTemplate.opsForValue().get(redisTemplateUserObjectKey);办法获取工具,会操为难刁难象转换失落败,建议的办理办法是默认都采取 com.fastxml.jackson的ObjectMapper工具进行转换,也便是:

ObjectMapper objectMapper = new ObjectMapper();objectMapper.convertValue(Object fromValue, Class<T> toValueType);复制代码

该办法支持将任意类型的Object工具转换为相应的实体工具。