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\"}"

ObjectMapperJobDefinition 条目生成一个 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 而是使用 DecoratingStringHashMapperStringRedisTemplate.

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 并帮助我们确定优先顺序。