使用 Spring Data Redis 配置 Redis TTL

1、简介

在本教程中,我们将学习如何在 Spring Data Redis 中配置 key 的过期时间。

2、项目设置

假设我们有一个整合了 spring data redis 的 spring boot 项目,我们打算使用 redis 来管理用户的会话(Session)。

2.1、依赖

首先,在 pom.xml 中添加以下依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <version>3.0.4</version>
</dependency>

spring-boot-starter-data-redis 将传递依赖 spring-data-redislettuce-core

2.2、Redis 配置

其次,添加 RedisTemplate 配置:

@Configuration
public class RedisConfiguration {

    @Bean
    public RedisTemplate<String, Session> getRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Session> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        return redisTemplate;
    }
}

2.3、Model

第三,创建 Session model:

@RedisHash
public class Session {
    @Id
    private String id;
    private Long expirationInSeconds;
}

2.4、Redis Repository

最后,创建 SessionRepository,它提供与 Redis 的交互,以管理我们的 Session 实体:

public interface SessionRepository extends CrudRepository<Session, String> {}

3、设置 TTL 的方法

我们将介绍三种设置 TTL 的方法。

3.1、使用 @RedisHash

从最简单的开始。@RedisHash 允许我们为其 timeToLive 属性提供一个值:

@RedisHash(timeToLive = 60L)
public class Session {
    @Id
    private String id;
    private Long expirationInSeconds;
}

它以秒为单位取值。在上例中,我们将过期时间设置为 60 秒。当我们想为所有 Session 对象提供一个恒定值 TTL 时,这种方法非常有用。

3.2、使用 @TimeToLive

在前一种方法中,可以为所有 Session 对象设置相同的恒定 TTL。而这一种方法则更具动态性。使用 @TimeToLive,可以注解任何“数值属性”或“返回数值的方法”来设置 TTL:

@RedisHash(timeToLive = 60L)
public class Session {
    @Id
    private String id;
    @TimeToLive
    private Long expirationInSeconds;
}

这样,我们就可以动态设置每个 Session 对象的 TTL。与之前的方法一样,TTL 以秒为单位。@TimeToLive 的值取代了 @RedisHash(timeToLive)

3.3、使用 KeyspaceSettings

接下来,使用 KeyspaceSettings 设置 TTL。Keyspace 定义了用于创建 Redis Hash 实际 key 的前缀。现在,让我们为 Session 类定义 KeyspaceSettings

@Configuration
@EnableRedisRepositories(keyspaceConfiguration = RedisConfiguration.MyKeyspaceConfiguration.class)
public class RedisConfiguration {

    // Other configurations omitted

    public static class MyKeyspaceConfiguration extends KeyspaceConfiguration {

        @Override
        protected Iterable<KeyspaceSettings> initialConfiguration() {
            KeyspaceSettings keyspaceSettings = new KeyspaceSettings(Session.class, "session");
            keyspaceSettings.setTimeToLive(60L);
            return Collections.singleton(keyspaceSettings);
        }
    }
}

与之前的方法一样,我们指定了以秒为单位的 TTL。这种方法与 @RedisHash 非常相似。此外,如果我们不想使用 @EnableRepositories,也可以通过编程式的方式来设置:

@Configuration
public class RedisConfiguration {

    // Other configurations omitted

    @Bean
    public RedisMappingContext keyValueMappingContext() {
        return new RedisMappingContext(new MappingConfiguration(new IndexConfiguration(), new MyKeyspaceConfiguration()));
    }

    public static class MyKeyspaceConfiguration extends KeyspaceConfiguration {

        @Override
        protected Iterable<KeyspaceSettings> initialConfiguration() {
            KeyspaceSettings keyspaceSettings = new KeyspaceSettings(Session.class, "session");
            keyspaceSettings.setTimeToLive(60L);
            return Collections.singleton(keyspaceSettings);
        }
    }
}

4、比较

最后,让我们比较一下我们看过的三种方法,看看什么时候该使用哪一种。

@RedisHashKeyspaceSettings 都允许我们一次性为所有实体实例(Session)设置 TTL。而,@TimeToLive 允许我们为每个实体实例动态设置 TTL。

KeyspaceSettings 提供了一种方法,可以在一个地方设置多个实体的默认 TTL。而 @TimeToLive@RedisHash 则需要在每个实体类中进行设置。

@TimeToLive 的优先级最高,其次是 @RedisHash,最后是 KeyspaceSettings

5、Redis Key 过期事件

设置了 key 的过期时间后,我们可能还会对“过期事件”何时发生感兴趣。为此,框架提供了 RedisKeyExpiredEvent。让我们设置一个 EventListener 来监听 RedisKeyExpiredEvent

@Configuration
@EnableRedisRepositories(enableKeyspaceEvents = RedisKeyValueAdapter.EnableKeyspaceEvents.ON_STARTUP)
@Slf4j
public class RedisConfiguration {
    // Other configurations omitted

    @Component
    public static class SessionExpiredEventListener {
        @EventListener
        public void handleRedisKeyExpiredEvent(RedisKeyExpiredEvent<Session> event) {
            Session expiredSession = (Session) event.getValue();
            assert expiredSession != null;
            log.info("Session with key={} has expired", expiredSession.getId());
        }
    }
}

现在我们可以知道 Session 何时过期,可以在过期时执行一些其他逻辑:

2023-02-10T15:13:38.626+05:30  INFO 16874 --- [enerContainer-1] c.b.s.config.RedisConfiguration:
  Session with key=edbd98e9-7b50-45d8-9cf4-9c621899e213 has expired

6、总结

在本文中,我们介绍了通过 Spring Data Redis 设置 Redis TTL 的各种方法,以及如何监听 key 过期事件(RedisKeyExpiredEvent)。


参考:https://www.baeldung.com/spring-data-redis-ttl