一直在项目中使用redis,偶然遇到一个问题,你们项目中的redis用的是那种序列化?回想一下确实也没太注意,学艺不精,所以在网上查阅了资料,做一下总结。
一般在工作中使用redis存储的api都是使用spring data redis的 RedisTemplate 和 StringRedisTemplate,为啥spring提供了两个template呢,其实这里面是有点文章的。
RedisTemplate 和 StringRedisTemplate 的区别呢,主要在与序列化,StringRedisTemplate存储的key-val,用RedisTemplate去(操作)get(key)是取不出来的。RedisTemplate存储的key-val,用StringRedisTemplate去(操作)get(key)也是取不出来的。为啥呢?
来段RedisTemplate的源码:
private RedisSerializer<?> defaultSerializer = new JdkSerializationRedisSerializer();
private RedisSerializer keySerializer = null;
private RedisSerializer valueSerializer = null;
private RedisSerializer hashKeySerializer = null;
private RedisSerializer hashValueSerializer = null;
private RedisSerializer<String> stringSerializer = new StringRedisSerializer();
if (this.enableDefaultSerializer) {
if (this.keySerializer == null) {
this.keySerializer = this.defaultSerializer;
defaultUsed = true;
}
if (this.valueSerializer == null) {
this.valueSerializer = this.defaultSerializer;
defaultUsed = true;
}
if (this.hashKeySerializer == null) {
this.hashKeySerializer = this.defaultSerializer;
defaultUsed = true;
}
if (this.hashValueSerializer == null) {
this.hashValueSerializer = this.defaultSerializer;
defaultUsed = true;
}
}
当没有指定RedisTemplate的key/value/hashValue...序列化的时候,默认是使用 JdkSerializationRedisSerializer;
JdkSerializationRedisSerializer在存储时会转成字节数组进行存储;
对于 key = "AAAA" value = "cccc" 的情况, server 端运行的情况如下
"SET" "\xac\xed\x00\x05t\x00\x04AAAA" "\xac\xed\x00\x05t\x00\x04cccc"
"GET" "\xac\xed\x00\x05t\x00\x04AAAA"
在这种序列化下使用value自增的操作是会报类型错误的。
StringRedisTemplate使用的是StringRedisSerializer进行序列化。
public StringRedisTemplate() {
RedisSerializer<String> stringSerializer = new StringRedisSerializer();
this.setKeySerializer(stringSerializer);
this.setValueSerializer(stringSerializer);
this.setHashKeySerializer(stringSerializer);
this.setHashValueSerializer(stringSerializer);
}
StringRedisSerializer在序列化的时候会以String的形式存储
对于 key = "AAAA" value = "cccc" 的情况, server 端运行的情况如下:
"SET" "AAAA" "cccc"
"GET" "AAAA"
这也造成了RedisTemplate和StringRedisTemplate去操作相互key的时候,结果都是不成功的。
所以为了方便统一一点,都会在RedisTemplate中去配置以String形式存储的序列化
<!-- redis 序列化策略 ,通常情况下key值采用String序列化策略, -->
<!-- 如果不指定序列化策略,StringRedisTemplate的key和value都将采用String序列化策略; -->
<!-- 但是RedisTemplate的key和value都将采用JDK序列化 这样就会出现采用不同template保存的数据不能用同一个template操作的问题 -->
<bean id="stringRedisSerializer"
class="org.springframework.data.redis.serializer.StringRedisSerializer" />
<bean id='redisWriteTemplate' class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisWriteConnectionFactory" />
<property name="keySerializer" ref="stringRedisSerializer" />
<property name="hashKeySerializer" ref="stringRedisSerializer" />
</bean>
这里只指定了部分key的StringRedisSerializer,当然如果需要的话也可以指定value的StringRedisSerializer序列化
<property name="hashKeySerializer" ref="stringSerializer" />
<property name="hashValueSerializer" ref="stringSerializer"/>
这样配置的话RedisTemplate的 key、val都会以String的形式存储。
相率来说的话JdkSerializationRedisSerializer要比StringRedisSerializer高一些。
一般存储的可能会不仅仅是String类型的对象,那么在存储的时候只需要序列化成json串存储就可以了,然后get出来之后再把json串解析成相应的对象。
当然也不仅仅只有这两种序列化,spring还提供了其他几种。这两种最常用一些。有兴趣的可以再深入理解,小弟就先介绍到这里了。
如有写的不对的地方,勿喷,还请谅解。
面试题:你们项目中的redis使用的是什么序列化?为什么?几种序列化有什么区别?
参考资料:
https://www.cnblogs.com/edwinchen/p/3816938.html