Spring Data操作Redis时,发现key值出现 \xac\xed\x00\x05t\x00\tb

来源:互联网 发布:环形网络拓扑结构特点 编辑:程序博客网 时间:2024/06/05 03:42

最近在研究redis,以及spring data对redis的支持发现了一个奇怪的现象

先说现象吧,通过redisTemplate下的opsForHash方法存储hash类型的值,操作成功以后,去redis控制台显示keys * 的时候,发现一个奇怪的现象,插入的hash类型的key前面会有一堆的\xac\xed\x00\x05t\x00\tb 这种东西,见图1

 

图1

(图1)

 

看见了吗?就是第二行那一串自己冒出来的东西,分析spring-data的org.springframework.data.redis.core.RedisTemplate源代码以后发现:

[java] view plaincopy
  1. private RedisSerializer<?> defaultSerializer = new JdkSerializationRedisSerializer();  
  2.   
  3. private RedisSerializer keySerializer = null;  
  4. private RedisSerializer valueSerializer = null;  
  5. private RedisSerializer hashKeySerializer = null;  
  6. private RedisSerializer hashValueSerializer = null;  
  7. private RedisSerializer<String> stringSerializer = new StringRedisSerializer();  

发现了一个:

[java] view plaincopy
  1. private RedisSerializer<?> defaultSerializer = new JdkSerializationRedisSerializer();  

因为spring操作redis是在jedis客户端基础上进行的,而jedis客户端与redis交互的时候协议中定义是用byte类型交互,jedis中提供了string类型转为byte[]类型,但是看到spring-data-redis中RedisTemplate<K, V>在操作的时候k,v是泛型的,所以RedisTemplate中有了上面那段代码,在没有特殊定义的情况下,spring默认采用defaultSerializer = new JdkSerializationRedisSerializer();来对key,value进行序列化操作,在经过查看JdkSerializationRedisSerializer中对序列化的一系列操作,发现如下代码:

[java] view plaincopy
  1. private Converter<Object, byte[]> serializer = new SerializingConverter();  
  2. public byte[] serialize(Object object) {  
  3.     if (object == null) {  
  4.         return SerializationUtils.EMPTY_ARRAY;  
  5.     }  
  6.     try {  
  7.         return serializer.convert(object);  
  8.     } catch (Exception ex) {  
  9.         throw new SerializationException("Cannot serialize", ex);  
  10.     }  
  11. }  

序列化支持的是Object对象,调用了SerializingConverter类下的convert方法转换对象,转换对象的方法是:

[java] view plaincopy
  1. private final Serializer<Object> serializer;  
  2. /** 
  3.  * Serializes the source object and returns the byte array result. 
  4.  */  
  5. public byte[] convert(Object source) {  
  6.     ByteArrayOutputStream byteStream = new ByteArrayOutputStream(128);  
  7.     try  {  
  8.         this.serializer.serialize(source, byteStream);  
  9.         return byteStream.toByteArray();  
  10.     }  
  11.     catch (Throwable ex) {  
  12.         throw new SerializationFailedException("Failed to serialize object using " +  
  13.                 this.serializer.getClass().getSimpleName(), ex);  
  14.     }  
  15. }  

原因其实就出现在这里,解决的办法就是手动定义序列化的方法,spring-data-redis中还提供了一个序列化的类专门针对string类型的序列化org.springframework.data.redis.serializer.StringRedisSerializer这个类,可以在xml里面指定:

[html] view plaincopy
  1. <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"  
  2.     p:connection-factory-ref="jedisConnectionFactory">  
  3.     <property name="keySerializer">  
  4.         <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />  
  5.     </property>  
  6.     <property name="valueSerializer">  
  7.         <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />  
  8.     </property>  
  9.     <property name="hashKeySerializer">  
  10.         <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />  
  11.     </property>  
  12.     <property name="hashValueSerializer">  
  13.         <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />  
  14.     </property>  
  15. </bean>  

其中我将redis中基础类型的key,value和hash类型的key,value都指定为StringRedisSerializer类来进行序列化,然后发现又报错了,找了一会发现我的代码中:

[java] view plaincopy
  1. public void setBank(final Bank bank) {  
  2.     // TODO setBank  
  3.     final String key = String.format("bank:%s", bank.getId());  
  4.     final Map<String, Object> properties = new HashMap<String, Object>();  
  5.       
  6.     properties.put("id", bank.getId());  
  7.     properties.put("name", bank.getBank_name());  
  8.       
  9.     redisTemplate.opsForHash().putAll(key, properties);  
  10. }  

bank.getId是Integer类型的,因为Hashmap中的key和value也会进行序列化操作,而StringRedisSerializer中的serialize方法只接收String类型的值,如下:

[java] view plaincopy
  1. public byte[] serialize(String string) {  
  2.     return (string == null ? null : string.getBytes(charset));  
  3. }  

所以这里的类型转换报错了,二话不说直接bank.getId().toString(),执行成功,然后进入redis控制台打开查看发现那堆恶心巴拉的\xac\xed\x00\x05t\x00\tb没有了,大功告成了

         


(红色部分)

其实redis在使用中,必须要提前考虑的就是内存的占用问题(博客中另外一篇文章很经典,阐述了一个外国人做的测试,同样的存储可以节约几十G的内存【Redis 内存优化】节约内存:Instagram的Redis实践),在设计的时候使用hash可以节约很多的内存,而存储的时候如果每条数据就放一堆\xac\xed\x00\x05t\x00\tb这个东西,肯定是无法直视的

------------------------------------------------------------------------------------------------

以上是个人的拙见,如有哪里分析的不对的地方,欢迎拍砖


原文地址:http://blog.csdn.net/yunhaibin/article/details/9001198

1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 眼睛里膜起来了怎么办 眼睛一边大一边小怎么办 眼白膜鼓起来了怎么办 主持问答环节没人提问怎么办 转学原学校不给怎么办 村长借东西不还怎么办 村长不上报建房申请怎么办 村长不上报建房手续申请怎么办 村长不给村民盖章怎么办? 找村干部办事难怎么办 洪洞县村长不给我盖章怎么办 睾丸穿刺取精只配到6个胚胎怎么办 孩子一只耳朵听不到声音怎么办 孕早期孕囊生长慢怎么办 试管2次不着床怎么办? pescm球员年龄大了怎么办 实况足球俱乐部经理球员老了怎么办 你不是我的菜怎么办 苹果平板电脑耳机有回音怎么办 obs直播有电流音怎么办 语音里网吧很吵怎么办 电脑k歌有延迟怎么办 想开个跆拳道馆怎么办营业执照? 壶嘴拐弯处漏水怎么办 裂纹茶壶嘴坏了怎么办 小孩刚上学怕她上火怎么办 在幼儿园小朋友不愿叠衣服怎么办 孩子在家听话幼儿园不听话怎么办 变魔术时观众说看过这个怎么办 孕妇8个月摔跤了怎么办 孩子吃了残奶怎么办 小米手机变卡了怎么办 主持时说错话了怎么办 小鲜肉老了不红怎么办 同学聚会大家玩手机你怎么办 率土之滨被掠夺怎么办 戒指戴手上取不下来怎么办 择离开我我该怎么办 解小手解不出来怎么办 学生把班里的班费弄丢了怎么办 班里选的班长成绩差怎么办