Spring Data REDIS-具有奇怪前缀的哈希键,并且HSCAN无法正确返回结果

时间:2019-05-03 10:02:58

标签: java redis spring-data-redis lettuce

我正在使用带有spring-data-redis:jar:2.0.9的spring boot(无关),它使用生菜连接到我的REDIS。我正在使用包含大约100个键的哈希结构。在这些键下,我放置了一些类型也不相关的对象:

private static final String HASH_KEY_NAME = "myspecialhashes:somekey";

@Autowired
private RedisTemplate<String, MyDto> myDtoRedisTemplate;

现在,我只是使用对象的ID作为键将对象列表放入哈希中:

myDtoRedisTemplate.opsForHash().put(HASH_KEY_NAME, dto.getId(), dto);

这很好用,并且从哈希中检索所有元素也很好,并且仅检索键

List allDtosRaw = myDtoRedisTemplate.opsForHash().values(HASH_KEY_NAME);

还列出密钥时:

myDtoRedisTemplate.boundHashOps(HASH_KEY_NAME).keys()

看起来不错,并且返回的键集开头为:

(java.util.LinkedHashSet<E>) [fakeservicetest:dummy3:write, fakesingle:dummy:sub1:write, ....

由于有很多键,我希望能够使用HSCAN使用令牌来过滤对象列表 STARTING ,而不是获取所有键并在我的Java应用程序中对其进行过滤。因此,这就是我执行HSCAN来获取所有以“ fake”开头的哈希条目的方式。

List filteredDtosRaw = new LinkedList<>();
ScanOptions scanOptions = ScanOptions.scanOptions().match("fake*").count(10000).build();
Cursor cursor = myDtoRedisTemplate.boundHashOps(HASH_KEY_NAME).scan(scanOptions);
        cursor.forEachRemaining(filteredDtosRaw ::add);

不幸的是,这将返回零结果。我正在尝试各种方法来解决该问题并获得一些结果。最终,我转向redis命令行,以了解REDIS对所有这些想法的看法

redis-cli HSCAN "myspecialhashes:somekey" 0 MATCH "fake*" COUNT 1000

结果确实为零。接下来的事情是查看其中所有的键,并查看哈希中的实际内容

redis-cli HGETALL "myspecialhashes:somekey"

结果类似于:

1) "0"
2)  1) "\xac\xed\x00\x05t\x00\x1cfakeservicetest:dummy3:write"
    2) "{\"@class\":\"
.....

看起来,这些键包含一些Unicode字符的前缀。这可能是由于String序列化(我已经在使用调试器将字符串放入REDIS之前检查过这些字符串,并且它们在一开始不包含任何不可见的字符)。因此,现在我有了一个可行的解决方法:我可以搜索“ * fake *”,它在REDIS CLI和Spring Data Redis中都可以使用。而且由于只希望以“ fake”开头的内容,我可以使用String.startsWith在Java应用程序中对此进行过滤。但是,由于我不喜欢变通办法,所以我想知道我是否正确使用了spring数据redis,或者在序列化用于REDIS的字符串和用于SCAN的字符串时序列化有一些不一致?

1 个答案:

答案 0 :(得分:0)

好,我现在知道了。我已经为字符串序列化程序配置了redis序列化程序,但似乎哈希键需要为哈希键项单独设置序列化程序。那些“奇怪的Unicode字符”是JdkSerializer的结果

@Bean
public RedisTemplate<String, MyDto> redisTemplateMyDto() {
    final RedisTemplate<String, MyDto> template = new RedisTemplate<String, MyDto>();
    template.setConnectionFactory(redisConnectionFactory);
    template.setKeySerializer(new StringRedisSerializer());
    template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
    template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
    return template;
}

更改为

@Bean
public RedisTemplate<String, MyDto> redisTemplateMyDto() {
    final RedisTemplate<String, MyDto> template = new RedisTemplate<String, MyDto>();
    template.setConnectionFactory(redisConnectionFactory);
    template.setHashKeySerializer(new StringRedisSerializer());
    template.setKeySerializer(new StringRedisSerializer());
    template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
    template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
    return template;
}