Spring Redis - 主条目过期后索引未删除

问题描述 投票:0回答:3

我正在使用 Spring 数据存储库保存新条目。每个条目的 TTL 为 10 秒。

当我保存带有索引的条目时,这就是我在 Redis 中得到的内容

127.0.0.1:6379> keys *
1) "job:campaignId:aa"
2) "job:a6d6e491-5d75-4fd0-bd8e-71692f6d18be"
3) "job:recipient:dd"
4) "job:a6d6e491-5d75-4fd0-bd8e-71692f6d18be:phantom"
5) "job:listId:cc"
6) "job:accountId:bb"
7) "job"
8) "job:a6d6e491-5d75-4fd0-bd8e-71692f6d18be:idx"

过期后,我还有数据:

127.0.0.1:6379> keys *
1) "job:campaignId:aa"
2) "job:recipient:dd"
3) "job:listId:cc"
4) "job:accountId:bb"
5) "job"
6) "job:a6d6e491-5d75-4fd0-bd8e-71692f6d18be:idx"

没有任何TTL。

他们为什么不删除自己?我怎么能这么做呢?

spring redis spring-data spring-data-redis
3个回答
33
投票

Spring Data Redis 存储库使用多个 Redis 功能将域对象持久保存在 Redis 中。

域对象主要存储在哈希中 (

job:a6d6e491-5d75-4fd0-bd8e-71692f6d18be
)。任何过期都会直接应用于哈希,以便 Redis 可以使密钥过期。 Spring Data Redis 还维护二级索引(
job:campaignId:aa
job:recipient:dd
)以提供特定字段值的查找。集合内的单个元素不能过期。只有整个数据结构才会过期,但这不是您想要做的事情,因为所有未过期的元素都会以这种方式消失。

因此 Spring Data Redis 将原始哈希的副本保留为幻影哈希 (

job:a6d6e491-5d75-4fd0-bd8e-71692f6d18be:phantom
),并具有稍长的 TTL。

Spring Data Redis 订阅按键事件(通过设置

@EnableRedisRepositories(enableKeyspaceEvents = EnableKeyspaceEvents.ON_STARTUP
)来监听过期事件。一旦原始哈希过期,Spring Data Redis 就会加载幻像哈希来执行清理(从二级索引中删除引用)。

未执行数据清理的原因可能有多种:

  1. 如果您运行控制台应用程序只是为了插入数据并终止,则到期会删除哈希值,但不会执行索引清理,因为您的应用程序不再运行。 Redis 发布的任何事件都是暂时的,如果您的应用程序没有监听,那么这些事件就会丢失
  2. 如果您仅使用
    @EnableRedisRepositories
    启用了存储库支持(未启用 keyspace-events),则 Keyspace 事件侦听器不处于活动状态,并且 Spring Data Redis 不会订阅任何到期事件。

0
投票

主条目过期后索引未被删除的另一个可能原因是在键空间中使用冒号:

@RedisHash(value = "app-name:entity-name")

根据以下主题,键空间中不支持冒号:

  1. https://github.com/spring-projects/spring-data-redis/issues/2096
  2. https://github.com/spring-projects/spring-data-redis/pull/2100#issuecomment-881256388

你也可以通过查看keyspace事件处理方法的实现来验证这一点

org.springframework.data.redis.core.RedisKeyValueAdapter.MappingExpirationListener#onMessage
org.springframework.data:spring-data-redis:3.1.0)。


-1
投票

如果不设置过期时间,则不会自动删除任何键/值。

因此要自动删除数据,您必须设置过期时间。

redis> SET mykey "Hello"
"OK"
redis> EXPIRE mykey 10
(integer) 1

参考:https://redis.io/commands/expire

下面是Spring代码片段,用于向redis添加数据并设置过期时间

@Component
public class RedisUtil {
    @Autowired
    private RedisTemplate<String, String> template;

    @Resource(name = "redisTemplate")
    ValueOperations<String, String> ops;

    public boolean addValue(String key, String value) {

        if (template.hasKey(Constants.REDIS_KEY_PREFIX + key)) {
            // key is already there
            return false;
        } else {
            ops.set(Constants.REDIS_KEY_PREFIX + key, value);
            template.expireAt(Constants.REDIS_KEY_PREFIX + key, 10);
        }
        return true;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.