RedisTemplate 哈希值序列化器用于具有多种类型的嵌套对象
RedisTemplate hashvalue serializer to use for nested object with multiple types
我正在尝试使用 Redis 为我的实体存储一些缓存数据,该实体内部有不同类型的字段,例如,
public class Job {
private String id;
private Date createTime; //Long
private String submitterName;
private JobDefinition jobDef; //Another class
}
有更多的字段,由于有几个字段比其他字段更新更频繁,我决定将这个 job
保存为 Redis 中的 Hashmap,每个字段作为键。这里像 jobDef
这样的嵌套对象并不重要所以我使用 Jackson2JsonRedisSerializer
作为 hashValueSerializer
用于 RedisTemplate
并且 jobDef
obj 将被序列化为 long JSON 字符串,这对我来说完全没问题。
但我不知道如何有效地反序列化整个 job
对象从 Redis 返回。我设置为反序列化器的类型类似于 Jackson2JsonRedisSerializer(Map.class)
但它在反序列化 String 键和值时会报错。
这是否是 RedisTemplate
的无效用法,或者我应该如何为它配置我的序列化程序?
编辑:
添加更多代码细节,
@Autowired
private StringRedisTemplate redisTemplate; //Here I'm using a String template as I need to use the same redisTemplate for some key-value/list operations too
Map jobHash= new ObjectMapper().convertValue(job, Map.class);
redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer(Map.class));
redisTemplate.opsForHash().putAll("job:"+job.getId(), jobHash); //After this the job hash shows up in Redis as I expected, while the jobDef member is serialized and saved as a JSON string
Map jobMap = redisTemplate.opsForHash().entries("job:" + job.getId()); //But this won't work as it'll throw exception complaining cannot deserialize a String value to Map. But when I set Jackson2JsonRedisSerializer(String.class) it throws exception that cannot resolve the byte code
第二次编辑:
如果在 RedisTemplate
中使用 JdkSerializationRedisSerializer
作为 HashValueSerializer 那么反序列化工作正常,但是使用这个的缺点是存储在 Redis 中的值与使用时的人类可读字符串值不同Jackson2JsonRedisSerializer
。
Jackson2JsonRedisSerializer
不包括到实际散列结构中的映射信息。
生成的 Redis 哈希结果类似于:
127.0.0.1:6379> hgetall job:1
1) "id"
2) "\"1\""
3) "createTime"
4) "1455778716799"
5) "submitterName"
6) "\"Jon Snow\""
7) "jobDef"
8) "{\"def\":\"nightwatch\"}"
ObjectMapper
为 JobDefinition
条目生成一个 LinkedHashMap
,由于类型未知,无法反序列化。
使用 GenericJackson2JsonRedisSerializer
包含类型信息,因此生成的 Redis HASH 如下所示:
127.0.0.1:6379> hgetall job:1
1) "id"
2) "\"1\""
...
7) "jobDef"
8) "{\"@class\":\"java.util.LinkedHashMap\",\"def\":\"nightwatch\"}"
这允许正确反序列化值。
另一种方法是 不 使用特定的 HashValueSerializer
而是使用 DecoratingStringHashMapper
和 StringRedisTemplate
.
DecoratingStringHashMapper mapper = new DecoratingStringHashMapper<Job>(
new JacksonHashMapper<Job>(Job.class));
template.opsForHash().putAll("job:" + job.id, mapper.toHash(job));
Map jobMap = template.opsForHash().entries("job:" + job.id);
DecoratingStringHashMapper
会产生一个Redis Hash如下:
127.0.0.1:6379> hgetall job:1
1) "id"
2) "1"
3) "createTime"
4) "1455780810643"
5) "submitterName"
6) "Jon Snow"
7) "jobDef"
8) "{def=nightwatch}"
遗憾的是没有Jackson2HashMapper
。请投票给 DATAREDIS-423 并帮助我们确定优先顺序。
我正在尝试使用 Redis 为我的实体存储一些缓存数据,该实体内部有不同类型的字段,例如,
public class Job {
private String id;
private Date createTime; //Long
private String submitterName;
private JobDefinition jobDef; //Another class
}
有更多的字段,由于有几个字段比其他字段更新更频繁,我决定将这个 job
保存为 Redis 中的 Hashmap,每个字段作为键。这里像 jobDef
这样的嵌套对象并不重要所以我使用 Jackson2JsonRedisSerializer
作为 hashValueSerializer
用于 RedisTemplate
并且 jobDef
obj 将被序列化为 long JSON 字符串,这对我来说完全没问题。
但我不知道如何有效地反序列化整个 job
对象从 Redis 返回。我设置为反序列化器的类型类似于 Jackson2JsonRedisSerializer(Map.class)
但它在反序列化 String 键和值时会报错。
这是否是 RedisTemplate
的无效用法,或者我应该如何为它配置我的序列化程序?
编辑: 添加更多代码细节,
@Autowired
private StringRedisTemplate redisTemplate; //Here I'm using a String template as I need to use the same redisTemplate for some key-value/list operations too
Map jobHash= new ObjectMapper().convertValue(job, Map.class);
redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer(Map.class));
redisTemplate.opsForHash().putAll("job:"+job.getId(), jobHash); //After this the job hash shows up in Redis as I expected, while the jobDef member is serialized and saved as a JSON string
Map jobMap = redisTemplate.opsForHash().entries("job:" + job.getId()); //But this won't work as it'll throw exception complaining cannot deserialize a String value to Map. But when I set Jackson2JsonRedisSerializer(String.class) it throws exception that cannot resolve the byte code
第二次编辑:
如果在 RedisTemplate
中使用 JdkSerializationRedisSerializer
作为 HashValueSerializer 那么反序列化工作正常,但是使用这个的缺点是存储在 Redis 中的值与使用时的人类可读字符串值不同Jackson2JsonRedisSerializer
。
Jackson2JsonRedisSerializer
不包括到实际散列结构中的映射信息。
生成的 Redis 哈希结果类似于:
127.0.0.1:6379> hgetall job:1
1) "id"
2) "\"1\""
3) "createTime"
4) "1455778716799"
5) "submitterName"
6) "\"Jon Snow\""
7) "jobDef"
8) "{\"def\":\"nightwatch\"}"
ObjectMapper
为 JobDefinition
条目生成一个 LinkedHashMap
,由于类型未知,无法反序列化。
使用 GenericJackson2JsonRedisSerializer
包含类型信息,因此生成的 Redis HASH 如下所示:
127.0.0.1:6379> hgetall job:1
1) "id"
2) "\"1\""
...
7) "jobDef"
8) "{\"@class\":\"java.util.LinkedHashMap\",\"def\":\"nightwatch\"}"
这允许正确反序列化值。
另一种方法是 不 使用特定的 HashValueSerializer
而是使用 DecoratingStringHashMapper
和 StringRedisTemplate
.
DecoratingStringHashMapper mapper = new DecoratingStringHashMapper<Job>(
new JacksonHashMapper<Job>(Job.class));
template.opsForHash().putAll("job:" + job.id, mapper.toHash(job));
Map jobMap = template.opsForHash().entries("job:" + job.id);
DecoratingStringHashMapper
会产生一个Redis Hash如下:
127.0.0.1:6379> hgetall job:1
1) "id"
2) "1"
3) "createTime"
4) "1455780810643"
5) "submitterName"
6) "Jon Snow"
7) "jobDef"
8) "{def=nightwatch}"
遗憾的是没有Jackson2HashMapper
。请投票给 DATAREDIS-423 并帮助我们确定优先顺序。