博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
RedisTemplate的key默认序列化器问题
阅读量:4106 次
发布时间:2019-05-25

本文共 3060 字,大约阅读时间需要 10 分钟。

redis的客户端换成了spring-boot-starter-data-redis,碰到了一个奇怪的问题,

在同一个方法中

1.先hset,再hget,正常获得数据。

在不同的方法中 先hset,再hget获取不到数据,通过redis的monitor监控发现了命令的问题:

实际我的key为JK_HASH:csrk,hashkey为user,但是根据上图所示,实际执行的命令多了好多其他字符,这是什么原因呢?

在服务器端先确认发现实际有这个Hash,通过hset可以得到正确的数据,所以第一次执行hset的时候命令是正常的,问题可能出现在hget上面,先打开源码看一下

@SuppressWarnings("unchecked")	public HV get(K key, Object hashKey) {		final byte[] rawKey = rawKey(key);		final byte[] rawHashKey = rawHashKey(hashKey);		byte[] rawHashValue = execute(new RedisCallback
() { public byte[] doInRedis(RedisConnection connection) { return connection.hGet(rawKey, rawHashKey); } }, true); return (HV) deserializeHashValue(rawHashValue); }

从这里可以看到实际上传给redis的都是byte数据,而byte数组是rawKey和rawHashKey生成的,先看下rawKey方法

@SuppressWarnings("unchecked")	byte[] rawKey(Object key) {		Assert.notNull(key, "non null key required");		if (keySerializer() == null && key instanceof byte[]) {			return (byte[]) key;		}		return keySerializer().serialize(key);	}
然后进一步跟踪keySerializer()方法
RedisSerializer keySerializer() {		return template.getKeySerializer();	}
public RedisSerializer
getKeySerializer() { return keySerializer; }

最后跟踪到是RedisTemplate中的属性keySerializer导致的,而通过打印keySerializer的class发现 默认使用的是org.springframework.data.redis.serializer.JdkSerializationRedisSerializer,但它是如何进行初始化的呢,默认的构造函数中并没有对该属性进行初始化。

根据RedisTemplate的类关系发现它是继承RedisAccessor的,而此类是实现的org.springframework.beans.factory.InitializingBean接口,这个接口有个特性,凡是继承该接口的类,在初始化bean的时候会执行afterPropertiesSet方法。

而afterPropertiesSet方法中,确实对keySerializer进行了初始化:

public void afterPropertiesSet() {

super.afterPropertiesSet();
boolean defaultUsed = false;
if (defaultSerializer == null) {
defaultSerializer = new JdkSerializationRedisSerializer(
classLoader != null ? classLoader : this.getClass().getClassLoader());
}
if (enableDefaultSerializer) {
if (keySerializer == null) {
keySerializer = defaultSerializer;
defaultUsed = true;
}
if (valueSerializer == null) {
valueSerializer = defaultSerializer;
defaultUsed = true;
}
if (hashKeySerializer == null) {
hashKeySerializer = defaultSerializer;
defaultUsed = true;
}
if (hashValueSerializer == null) {
hashValueSerializer = defaultSerializer;
defaultUsed = true;
}
}
if (enableDefaultSerializer && defaultUsed) {
Assert.notNull(defaultSerializer, "default serializer null and not all serializers initialized");
}
if (scriptExecutor == null) {
this.scriptExecutor = new DefaultScriptExecutor<K>(this);
}
initialized = true;
}

在这里可以看到默认使用的正是org.springframework.data.redis.serializer.JdkSerializationRedisSerializer,而问题正在这里,通过查询可以发现序列化器有这些,而在这里我们需要使用的是StringRedisSerializer

加入如下代码:

@Autowired(required = false)	public void setRedisTemplate(RedisTemplate redisTemplate) {	    RedisSerializer stringSerializer = new StringRedisSerializer();	    redisTemplate.setKeySerializer(stringSerializer);	    redisTemplate.setValueSerializer(stringSerializer);	    redisTemplate.setHashKeySerializer(stringSerializer);	    redisTemplate.setHashValueSerializer(stringSerializer);	    this.redisTemplate = redisTemplate;	}
重新进行测试,方法1hset,方法2hget,方法2能拿到正确的数据,完毕。

你可能感兴趣的文章
USB入门系列之三-----USB的电气特性
查看>>
USB入门系列之四 —— USB的线缆以及插头、插座【转】
查看>>
USB入门系列之五 —— USB设备的插入检测机制
查看>>
USB入门系列之六 —— USB设备的枚举过程
查看>>
USB入门系列之七 —— USB的描述符及各种描述符之间的依赖关系【转】
查看>>
LwIP移植心得[转]
查看>>
LWIP ethernetif.c分析
查看>>
wireshark报The capture session could not be initiated 错误
查看>>
MDK中加载指定文件的技巧
查看>>
stm32 堆和栈(stm32 Heap & Stack)【worldsing笔记】
查看>>
STM32 keil mdk启动代码发分析 .
查看>>
解析 STM32 的启动过程(写的不错)
查看>>
应用层和传输层的关系
查看>>
802.11协议用到的简写
查看>>
802.11 学习笔记
查看>>
lwip--有趣的数组定义(预处理)
查看>>
lwIP配置文件opt.h和lwipopts.h初步分析
查看>>
lwIP配置文件opt.h和lwipopts.h初步分析
查看>>
lwIP ARP协议分析
查看>>
智能卡操作系统(COS),什么是智能卡操作系统(COS)
查看>>