首页 > 解决方案 > 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,但如果存储库方法可以返回非空值列表就足够了。

(是的,我知道幻影行为,但我认为它与我想要的无关)

标签: javaspringredisspring-data

解决方案


正如@Enoobong 提到的,有一个未 解决的问题https://jira.spring.io/browse/DATAREDIS-570(今年 9 月添加了一个解决方法)它开放了 5 年。

这意味着你应该非常小心地使用带有 TTL 的 RedishHash:

  • 确保您的 Redis 服务器允许您的应用程序“配置”键空间事件
  • 确保您有来自 github 问题的解决方法

但仍不建议将其作为生产就绪解决方案(我的意思是从应用注释配置 kayspace 事件),因此请考虑将其放入应用程序逻辑中,以保持调度程序删除过时的记录。此外,这意味着您需要处理从存储库返回的空值,直到该问题得到解决。


推荐阅读