4

我正在尝试使用 Redis 为我的实体存储一些缓存数据,其中包含不同类型的字段,例如,

public class Job {
    private String id;
    private Date createTime; //Long
    private String submitterName;
    private JobDefinition jobDef;  //Another class
}

有更多字段,并且由于几个字段的更新频率比其他字段更频繁,我决定将其保存job为 Redis 中的 Hashmap,每个字段作为键。在这里嵌套对象jobDef并不重要,所以我使用Jackson2JsonRedisSerializeras hashValueSerializerforRedisTemplatejobDefobj 将被序列化为长 JSON 字符串,这在我的情况下完全没问题。

但我不知道如何有效地job从 Redis 反序列化整个对象。我设置为反序列化器的类型就像Jackson2JsonRedisSerializer(Map.class)但在反序列化字符串键和值时会抱怨。

那么这是一个无效的用法,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

第二次编辑:

如果使用JdkSerializationRedisSerializeras HashValueSerializerRedisTemplate则反序列化工作正常,但是使用这个的缺点是存储在 Redis 中的值与使用时不同的人类可读字符串值Jackson2JsonRedisSerializer

4

1 回答 1

13

Jackson2JsonRedisSerializer不包括映射信息到实际的散列结构中。生成的 Redis HASH 结果如下:

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一个。LinkedHashMapJobDefinition

使用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的,而是使用 aDecoratingStringHashMapperStringRedisTemplate.

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投票并帮助我们确定优先级。

于 2016-02-18T07:45:36.720 回答