java - Spring Data Redis Repository 为过期条目返回 null
问题描述
我CrudRepository
在我的 Spring Boot 应用程序中使用一个用于连接到 Redis,并@TimeToLive
在实体中使用一个带注释的字段来过期:
@RedisHash("keyspace")
public class MyRedisEntity {
@Id String key;
MyPojo pojo;
@TimeToLive Long ttl;
}
public interface MyRedisRepository extends CrudRepository<MyRedisEntity, String>{}
现在,当过期发生时,myRedisRepo.findAll()
为过期的实体返回 null。我发现 redis(或 spring-data redis)将所有插入的实体的 id 存储在一个集合中,其中键空间作为键:
redis-cli> smembers keyspace
0) key0
1) key1
2) key2
...
redis-cli> hgetall key0
(empty list or set)
我怀疑这个集合用于findAll
调用,返回 null 以表示由于过期而不再作为哈希图存在的 id。另外,我尝试使用监听器RedisKeyExpiredEvent
,在 中使用存储库的删除方法onApplicationEvent
,但这无济于事。
@Component
public class RedisExpirationListener implements ApplicationListener<RedisKeyExpiredEvent> {
private MyRedisRepository myRedisRepository;
@Autowired
public RedisExpirationListener(MyRedisRepository myRedisRepository) {
this.myRedisRepository = myRedisRepository;
}
@Override
public void onApplicationEvent(RedisKeyExpiredEvent redisKeyExpiredEvent) {
if (redisKeyExpiredEvent.getKeyspace().equals("keyspace")) {
myRedisRepository.deleteById(new String(redisKeyExpiredEvent.getId()));
}
}
}
我应该怎么做才能只获得非空条目?理想情况下,我希望将过期条目完全从 redis 中删除,因此不会出现在 中findAll
,但如果存储库方法可以返回非空值列表就足够了。
(是的,我知道幻影行为,但我认为它与我想要的无关)
解决方案
正如@Enoobong 提到的,有一个未 解决的问题https://jira.spring.io/browse/DATAREDIS-570(今年 9 月添加了一个解决方法)它开放了 5 年。
这意味着你应该非常小心地使用带有 TTL 的 RedishHash:
- 确保您的 Redis 服务器允许您的应用程序“配置”键空间事件
- 确保您有来自 github 问题的解决方法
但仍不建议将其作为生产就绪解决方案(我的意思是从应用注释配置 kayspace 事件),因此请考虑将其放入应用程序逻辑中,以保持调度程序删除过时的记录。此外,这意味着您需要处理从存储库返回的空值,直到该问题得到解决。
推荐阅读
- python-3.x - 如何使用 ImageDataGenerator.flow_from_directory 将每个类/标签保存在其他子文件夹中?
- angular - 将离子日期时间格式化为 Firebase 时间戳
- algorithm - O(n^2) 的空间复杂度
- javascript - 我们如何在单击时将Div用作完整按钮将激活其他div将处于非活动状态
- powershell - 如何知道 2 个视频之间的帧延迟,将音频从视频 1 同步到视频 2?
- android - 如何防止 android recaptcha 对话框关闭外部的 onclick?
- google-bigquery - GCP - 从 PubSub 到 BigQuery 的消息
- scala - scala模式匹配字符串序列中的值
- sql-server - 如果条目是通过在多个表中输入数据的存储过程进行的,如何从表中恢复数据
- python - 机器学习二分类