java - Spring Data REDIS - 带有奇怪前缀的散列键,HSCAN 没有正确返回结果

标签 java redis spring-data-redis lettuce

我正在使用带有 spring-data-redis:jar:2.0.9 的 spring boot(无关),它使用 lettuce 连接到我的 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 使用 token 过滤对象列表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

确实是零结果。下一步是查看 has 中的所有键并查看哈希中的实际内容

redis-cli HGETALL "myspecialhashes:somekey"

结果是这样的:

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

看来,这些键包含一些 Unicode 字符的前缀。这可能是由于字符串序列化(我在使用调试器将字符串放入 REDIS 之前已经检查过,并且它们的开头不包含任何不可见字符)。所以我现在有一个可行的解决方法:我可以搜索“*fake*”,它在 REDIS CLI 和 Spring Data Redis 中都有效。因为我只想拥有以“fake”开头的那些,所以我可以在我的 Java 应用程序中使用 String.startsWith 过滤它。但是因为我不喜欢解决方法,所以我想知道我是否错误地使用了 spring data redis,或者在序列化字符串以放入 REDIS 和 SCAN 中使用的字符串时是否存在一些不一致?

最佳答案

好的,我现在知道了。我已经为字符串序列化程序配置了 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;
}

关于java - Spring Data REDIS - 带有奇怪前缀的散列键,HSCAN 没有正确返回结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55967558/

相关文章:

java - 如何在 JPanel/JFrame 中显示 JasperReports Viewer ..?

java - 使用 JDBC Ping MySQL 服务器

redis - 在 Redis 中使用 WHERE 子句查询值

java - 在redis中处理复杂数据类型

java - 无法获取 Jedis 连接;无法从池中获取资源

Java - WHILE 中的 Swing 计时器,带有启用/禁用按钮

java.sql.Time 异常

redis - redis SLOWLOG 命令测量的是 CPU 时间还是实时?

Redis 客户端 Lettuce 命令超时与套接字超时

MongoDB 缓存或不缓存使用 Redis