-
2022-05-11 09:44:39
Redis序列化方式
1. JdkSerializationRedisSerializer
这是RestTemplate类默认的序列化方式。
优点:
反序列化时不需要提供类型信息(class),
缺点:需要实现Serializable接口
存储的为二进制数据
序列化后的结果非常庞大,是JSON格式的5倍左右,这样就会消耗redis服务器的大量内存2. StringRedisSerializer
是StringRedisTemplate默认的序列化方式,key和value都会采用此方式进行序列化,是被推荐使用的,对开发者友好,轻量级,效率也比较高。
3. GenericToStringSerializer
需要调用者给传一个对象到字符串互转的Converter
4. Jackson2JsonRedisSerializer
优点:
速度快,序列化后的字符串短小精悍,不需要实现Serializable接口。
缺点:此类的构造函数中有一个类型参数,必须提供要序列化对象的类型信息(.class对象),其在反序列化过程中用到了类型信息
5. GenericJackson2JsonRedisSerializer
与Jackson2JsonRedisSerializer大致相同,会额外存储序列化对象的包命和类名
更多相关内容 -
redis序列化方式
2019-04-25 14:38:00redis序列化方式 (内容复制别人的博客,留作学习笔记) spring-data-redis的序列化类有下面这几个: GenericToStringSerializer: 可以将任何对象泛化为字符串并序列化 Jackson2JsonRedisSerializer: 跟...redis序列化方式 (内容复制别人的博客,留作学习笔记)
spring-data-redis的序列化类有下面这几个:
GenericToStringSerializer: 可以将任何对象泛化为字符串并序列化
Jackson2JsonRedisSerializer: 跟JacksonJsonRedisSerializer实际上是一样的
JacksonJsonRedisSerializer: 序列化object对象为json字符串
JdkSerializationRedisSerializer: 序列化java对象(被序列化的对象必须实现Serializable接口)
StringRedisSerializer: 简单的字符串序列化
GenericToStringSerializer:类似StringRedisSerializer的字符串序列化
GenericJackson2JsonRedisSerializer:类似Jackson2JsonRedisSerializer,但使用时构造函数不用特定的类
参考以上序列化,自定义序列化类Jdk序列化速度快,占用空间大,不易查看,通过redis命令查看类似\xAC\xED\x00\x05t\x00\x011不方便
Hash最好还是用GenericJackson2JsonRedisSerializer在用spring-data-redis做redis缓存的时候,指定RedisTemplate的key和value序列化时遇到的问题。
RedisTemplate的key指定成StringRedisSerializer序列化会报类型转换错误,如XXX类不能转换成String。
使用Jackson2JsonRedisSerializer序列化的时候,如果实体类上没有set方法反序列化会报错。同时采用了StringRedisTemplate和RedisTemplate时注意
并且对存储String与存储Java对象采用不同的Template进行了简单的封装。spring-data-redis默认采用的序列化策略有两种,一种是String的序列化策略,一种是JDK的序列化策略。
StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。StringRedisSerializer
RedisTemplate默认采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。JdkSerializationRedisSerializer
推荐将所有Template的key都采用String的序列化方式,而value的序列化方式可以采用不同的序列化方式。(jreids自动选择)(这样还有一个好处就是不必string的也采用jdk的序列化从而导常用数据格式致为了存储数据结构浪费空间)
参考https://blog.csdn.net/y666666y/article/details/70212767
@Configuration public class RedisConfiguration { @SuppressWarnings("unchecked") @Bean(name = "objectRedisTemplate") public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); @SuppressWarnings("") Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(objectMapper); redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.afterPropertiesSet(); return redisTemplate; } }
-
Redis 序列化方式StringRedisSerializer、FastJsonRedisSerializer和KryoRedisSerializer
2017-11-30 23:14:43当我们的数据存储到Redis的时候,我们的键(key)和值(value)都是通过Spring提供的Serializer序列化到数据库的。RedisTemplate默认使用的是JdkSerializationRedisSerializer,StringRedisTemplate默认使用的是...当我们的数据存储到Redis的时候,我们的键(key)和值(value)都是通过Spring提供的Serializer序列化到数据库的。RedisTemplate默认使用的是JdkSerializationRedisSerializer,StringRedisTemplate默认使用的是StringRedisSerializer。
Spring Data JPA为我们提供了下面的Serializer:GenericToStringSerializer、Jackson2JsonRedisSerializer、JacksonJsonRedisSerializer、JdkSerializationRedisSerializer、OxmSerializer、StringRedisSerializer。
序列化方式对比:
- JdkSerializationRedisSerializer: 使用JDK提供的序列化功能。 优点是反序列化时不需要提供类型信息(class),但缺点是需要实现Serializable接口,还有序列化后的结果非常庞大,是JSON格式的5倍左右,这样就会消耗redis服务器的大量内存。
- Jackson2JsonRedisSerializer: 使用Jackson库将对象序列化为JSON字符串。优点是速度快,序列化后的字符串短小精悍,不需要实现Serializable接口。但缺点也非常致命,那就是此类的构造函数中有一个类型参数,必须提供要序列化对象的类型信息(.class对象)。 通过查看源代码,发现其只在反序列化过程中用到了类型信息。
问题描述
我们在用Spring data redis做redis缓存的时候,指定RedisTemplate的key和value序列化时遇到的问题。
- RedisTemplate的key指定成StringRedisSerializer序列化会报类型转换错误,如XXX类不能转换成String。
- 使用Jackson2JsonRedisSerializer序列化的时候,如果实体类上没有set方法反序列化会报错。
问题分析
问题1:使用StringRedisSerializer做key的序列化时,StringRedisSerializer的泛型指定的是String,传其他对象就会报类型转换错误,在使用@Cacheable注解是key属性就只能传String进来。把这个序列化方式重写了,将泛型改成Object。源码:
/** * 必须重写序列化器,否则@Cacheable注解的key会报类型转换错误 * * @authors yuhao.wang */ public class StringRedisSerializer implements RedisSerializer<Object> { private final Charset charset; private final String target = "\""; private final String replacement = ""; public StringRedisSerializer() { this(Charset.forName("UTF8")); } public StringRedisSerializer(Charset charset) { Assert.notNull(charset, "Charset must not be null!"); this.charset = charset; } @Override public String deserialize(byte[] bytes) { return (bytes == null ? null : new String(bytes, charset)); } @Override public byte[] serialize(Object object) { String string = JSON.toJSONString(object); if (string == null) { return null; } string = string.replace(target, replacement); return string.getBytes(charset); } }
问题2:我们放弃用jackjson来做value的序列化,使用FastJson来做。重写一些序列化器,并实现RedisSerializer接口。源码如下:
public class FastJsonRedisSerializer<T> implements RedisSerializer<T> { public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); private Class<T> clazz; public FastJsonRedisSerializer(Class<T> clazz) { super(); this.clazz = clazz; } @Override public byte[] serialize(T t) throws SerializationException { if (t == null) { return new byte[0]; } return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET); } @Override public T deserialize(byte[] bytes) throws SerializationException { if (bytes == null || bytes.length <= 0) { return null; } String str = new String(bytes, DEFAULT_CHARSET); return (T) JSON.parseObject(str, clazz); } }
新加入一种序列化KryoRedisSerializer。速度很快,源码如下:
import com.esotericsoftware.kryo.Kryo; import com.esotericsoftware.kryo.io.Input; import com.esotericsoftware.kryo.io.Output; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.SerializationException; import java.io.ByteArrayOutputStream; /** * @param <T> * @author yuhao.wang */ public class KryoRedisSerializer<T> implements RedisSerializer<T> { Logger logger = LoggerFactory.getLogger(KryoRedisSerializer.class); public static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; private static final ThreadLocal<Kryo> kryos = ThreadLocal.withInitial(Kryo::new); private Class<T> clazz; public KryoRedisSerializer(Class<T> clazz) { super(); this.clazz = clazz; } @Override public byte[] serialize(T t) throws SerializationException { if (t == null) { return EMPTY_BYTE_ARRAY; } Kryo kryo = kryos.get(); kryo.setReferences(false); kryo.register(clazz); try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); Output output = new Output(baos)) { kryo.writeClassAndObject(output, t); output.flush(); return baos.toByteArray(); } catch (Exception e) { logger.error(e.getMessage(), e); } return EMPTY_BYTE_ARRAY; } @Override public T deserialize(byte[] bytes) throws SerializationException { if (bytes == null || bytes.length <= 0) { return null; } Kryo kryo = kryos.get(); kryo.setReferences(false); kryo.register(clazz); try (Input input = new Input(bytes)) { return (T) kryo.readClassAndObject(input); } catch (Exception e) { logger.error(e.getMessage(), e); } return null; } }
自定义序列化的使用
/** * @author yuhao.wang */ @Configuration public class RedisConfig { /** * 重写Redis序列化方式,使用Json方式: * 当我们的数据存储到Redis的时候,我们的键(key)和值(value)都是通过Spring提供的Serializer序列化到数据库的。RedisTemplate默认使用的是JdkSerializationRedisSerializer,StringRedisTemplate默认使用的是StringRedisSerializer。 * Spring Data JPA为我们提供了下面的Serializer: * GenericToStringSerializer、Jackson2JsonRedisSerializer、JacksonJsonRedisSerializer、JdkSerializationRedisSerializer、OxmSerializer、StringRedisSerializer。 * 在此我们将自己配置RedisTemplate并定义Serializer。 * * @param redisConnectionFactory * @return */ @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class); // 全局开启AutoType,不建议使用 // ParserConfig.getGlobalInstance().setAutoTypeSupport(true); // 建议使用这种方式,小范围指定白名单 ParserConfig.getGlobalInstance().addAccept("com.xiaolyuh."); // 设置值(value)的序列化采用FastJsonRedisSerializer。 redisTemplate.setValueSerializer(fastJsonRedisSerializer); redisTemplate.setHashValueSerializer(fastJsonRedisSerializer); // 设置键(key)的序列化采用StringRedisSerializer。 redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.afterPropertiesSet(); return redisTemplate; } }
注意:fastjson在2017年3月爆出了在1.2.24以及之前版本存在远程代码执行高危安全漏洞。所以要使用ParserConfig.getGlobalInstance().addAccept("com.xiaolyuh.");指定序列化白名单。详情可以点击这里查看
参考:
-
Redis序列化方式比较
2019-03-09 23:20:351.Spring-Data-Redis支持的序列化策略 SpringBoot默认提高StringRedisTemplate和RedisTemplate,前者用于操作包含字符串的数据机构,后者则使用了JDK自带的序列化策略。 事实上StringRedisTemplate继承了...1.Spring-Data-Redis支持的序列化策略
SpringBoot默认提高StringRedisTemplate和RedisTemplate,前者用于操作包含字符串的数据机构,后者则使用了JDK自带的序列化策略。
事实上StringRedisTemplate继承了RedisTemplate,对key、value 、hashkey、hashvalue提供了不同的序列化策略:
public class StringRedisTemplate extends RedisTemplate<String, String> { public StringRedisTemplate() { this.setKeySerializer(RedisSerializer.string()); this.setValueSerializer(RedisSerializer.string()); this.setHashKeySerializer(RedisSerializer.string()); this.setHashValueSerializer(RedisSerializer.string()); } }
key 普通key,非hash
value 普通value,非hash
hashKey hash的filed
hashValue hash的valueRedisTemplate采用的默认的序列化策略JdkSerializationRedisSerializer。这种序列化策略实现了RedisSerializer接口,定义如下:
public interface RedisSerializer<T> { @Nullable byte[] serialize(@Nullable T var1) throws SerializationException; @Nullable T deserialize(@Nullable byte[] var1) throws SerializationException; }
serialize方法:将默认的对象转换成字节数组,以提供给RedisCollection操作。
deserialize方法:将RedisCollection读取带的byte[]数组转换为对象。StringRedisTemplate则使用了StringRedisSerializer来将字符串转换为字节数组,将读取到的字节数组转换为字符串。
2.Spring-Data-Redis的序列化类有下面这几个:
GenericToStringSerializer: 可以将任何对象泛化为字符串并序列化
Jackson2JsonRedisSerializer: 跟JacksonJsonRedisSerializer实际上是一样的
JacksonJsonRedisSerializer: 序列化object对象为json字符串
JdkSerializationRedisSerializer: 序列化java对象(被序列化的对象必须实现Serializable接口),无法转义成对象
StringRedisSerializer: 简单的字符串序列化
GenericToStringSerializer:类似StringRedisSerializer的字符串序列化
GenericJackson2JsonRedisSerializer:类似Jackson2JsonRedisSerializer,但使用时构造函数不用特定的类参考以上序列化,自定义序列化类;key和hashKey:推荐使用 StringRedisSerializer: 简单的字符串序列化
value和hashValue:推荐使用GenericJackson2JsonRedisSerializer:类似Jackson2JsonRedisSerializer,但使用时构造函数不用特定的类
3.自定义序列化实例
配置自定义序列化策略:
@Configuration public class RedisConfig { private static Logger logger = LoggerFactory.getLogger(RedisConfig.class); @Bean(name = "springSessionDefaultRedisSerializer") public GenericJackson2JsonRedisSerializer getGenericJackson2JsonRedisSerializer() { return new GenericJackson2JsonRedisSerializer(); } @Bean public RedisTemplate<String, Object> getRedisTemplate( JedisConnectionFactory connectionFactory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>(); redisTemplate.setConnectionFactory(connectionFactory); redisTemplate.setDefaultSerializer(new GenericJackson2JsonRedisSerializer()); StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); redisTemplate.setKeySerializer(stringRedisSerializer); redisTemplate.setHashKeySerializer(stringRedisSerializer); return redisTemplate; } }
-
修改jfinal默认的redis序列化方式
2019-09-11 17:13:04jfinal 越来越流行, jfinal的redis插件默认的序列化方式是fst。 但是系统中其他项目中用的是spring data redis中的StringRedisTemplate,所有的value都是通过gson转化成String放进去的。 直接用jfinal的redis插件去... -
spring-data-redis序列化方式比较
2018-09-13 17:59:061. spring-data-redis支持的序列化策略 spring-data-redis默认采用的序列化策略有两种,一种是String的序列化策略,一种是JDK的序列化策略。...redisTemplate可自定义各种key和各种value的序列化方式:... -
SpringBoot修改Redis序列化方式
2018-08-16 17:40:00由于Springboot默认提供了序列化方式并不是非常理想,对于高要求的情况下,序列化的速度和序列化之后大小有要求的情况下,不能满足,所以可能需要更换序列化的方式。 这里主要记录更换序列化的方式以及其中一些出现... -
重写Redis序列化方式,redis可视化工具不乱码
2022-02-10 14:57:26重写Redis序列化方式,redis可视化工具不乱码 -
Spring之——整合Redis序列化方式StringRedisSerializer、FastJsonRedisSerializer和KryoRedisSerializer
2019-01-19 13:42:21当我们的数据存储到Redis的时候,我们的键(key)和值(value)都是通过Spring提供的Serializer序列化到数据库的。RedisTemplate默认使用的是JdkSerializationRedisSerializer,StringRedisTemplate默认使用的是... -
Redis序列化的几种方式
2019-12-12 15:03:36Redis序列化的几种方式 1.什么是Redis Redis是用C语言开发的一个开源的高性能键值对(key-value)数据库。它通过提供多种键值数据类型来适应不同场景下的存储需求,目前为止Redis支持的键值数据类型如下: 1、 字符... -
配置Redis序列化方式不生效问题
2021-12-14 10:38:38今天进行redis配置没有注意redis设置序列化方式的方法名称,导致redis序列化一直不成功。 @Configuration public class RedisConfig { @Bean public RedisTemplate<Object, Object> redisTemplate... -
SpringBoot整合Redis序列化
2022-03-24 12:07:30SpringBoot整合Redis序列化 -
SpringBoot Redis配置Fastjson进行序列化和反序列化实现
2020-10-16 03:12:55主要介绍了SpringBoot Redis配置Fastjson进行序列化和反序列化实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 -
Redis序列化对象的几种方式
2020-11-19 16:06:45对redis的value使用以下序列化方式进行序列化操作: 1:JdkSerializationRedisSerializer: 2:GenericJackson2JsonRedisSerializer 3:StringRedisSerializer 4:GenericFastJsonRedisSerializer 发现只有4:... -
Redis序列化对象的几种方式比较
2019-04-29 20:40:32对redis的value使用以下序列化方式进行序列化操作: 1:JdkSerializationRedisSerializer: 2:GenericJackson2JsonRedisSerializer 3:StringRedisSerializer 4:GenericFastJsonRedisSerializer 发现只有4:... -
三种序列化方式存取redis的方法
2021-03-06 22:27:17常见的的序列化反序列方式的效率:protoBuf(PB) > fastjson > jackson > hessian > xstream > java数据来自于:https://github.com/eishay/jvm-serializers/wiki所以我选择了java方式、jackson方式、... -
Redis几种序列化方式分析
2019-12-15 20:29:19一般redis的序列化方式主要有:字符串序列化、json序列化、xml序列化、jdk序列化,具体可查阅org.springframework.data.redis.serializer.RedisSerializer 的实现类,其中对于json序列化,官方实现的是jackson的序列... -
springboot集成redis序列化问题汇总
2022-04-03 22:54:09两种方案中都需要对序列化方式进行设置,否则会出现二进制格式的数据(不论是Redis desktop manager工具还是redis自带客户端黑窗口打开),如果需要查看数据则会影响观感,关于序列化方式设置底层都是对RedisSerializer... -
Redis实现自定义序列化方式
2020-07-30 11:06:451. 如何实现redis的序列化? 序列化:把对象转换为字节序列的过程称为对象的序列化。 反序列化:把字节序列恢复为对象的过程称为对象的反序列化。 序列化主要用于存储对象状态为另一种通用格式,比如存储为二进制、... -
redis 序列化对象问题
2022-01-17 11:54:10redis 序列化背景追根溯源RedisTemplateRedisSerializerJdkSerializationRedisSerializer总结 背景 最近在使用redis的发布订阅模式时,订阅类接收到的是字符串,习惯性的用JSON将字符串转成对象,结果就是各种报错,... -
SpringBoot2.3整合redis缓存自定义序列化的实现
2020-08-18 15:40:08主要介绍了SpringBoot2.3整合redis缓存自定义序列化的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 -
Redis 序列化
2021-12-03 14:25:53我们在用redis存储数据的时候,若果默认使用JDK的序列化方式,在Redis桌面花的工具中查看就会使乱码的情况,所以我们需要自定义redis的序列化方式,使用jackson2JsonRedisSerializer,复制下面这段即可 @... -
springdata redis配置序列化
2022-03-09 22:19:52今天遇到了一个问题,发现使用springdata redis添加缓存,key中多了一个前缀,\xac\xed\x00\x05t\x00\x1a,后来发现是因为序列化没有配置,配置代码如下 @Configuration public class RedisConfig { @Bean public... -
redis不同序列化方式性能对比
2019-12-15 20:43:14Redis的value序列化方式一般有两种:JSON方式和JDK方式 有以下几个序列化工具类: 第一次使用的是JDK方式进行测试 使用jdk方式需要pojo类实现Serializable接口 public void addByJDK() { //随机生五万条消息的一个... -
redis序列化_redis乱码_redis对象序列化
2021-12-01 18:18:40redis的hash数据类型,序列化方式默认使用的是对象序列化,会显示乱码 redisTemplate.setKeySerializer(new StringRedisSerializer()); //hash内部对象序列化,解决对象乱码 redisTemplate.setHashKeySerializer(new... -
Springboot集成Redis项目中Redis序列化配置
2022-02-08 21:32:19企业级项目中Redis序列化配置方案 -
redis 序列化 报错
2021-09-13 15:15:54nested exception is java.lang.ClassNotFoundException 1 对象序列化存入redis后,包名被修改,导致取出对象反序列化时包名不一致,报错 解决方案:清空redis 2 序列化与反序列化方式不对称也可能导致报错 解决...