Spring Boot 修改 Redis Value 但保留其过期时间(TTL)
在 Spring Boot 中使用 Redis 时,你一定需要过这种需求:更新某个 Redis 的 Value 值,但是不修改它的 TTL(Time To Live),也就是过期时间。
例如:使用 Redis 存储用户的 Session
,过期时间为半个小时。用户的每次访问,我们都需要更新用户 Session
的 Value 值,表示用户的最后一次访问时间。但是又不能修改用户 Session
的过期时间。
有 2 种方式可以实现。
先获取过期时间,再修改
这种方式最简单,也是最容易想到。在执行修改前,先获取到这个 Key 的剩余过期时间。然后通过 SET
命令执行修改,也就是完全覆盖这个 Key / Value,同时指定剩余的过期时间。
@Autowired
StringRedisTemplate stringRedisTemplate;
@Test
public void test() {
// session key
String key = "session::01";
// 先获取 key 的过期时间,单位是秒
Long expire = this.stringRedisTemplate.getExpire(key);
if (expire != null && expire > 0) {
// 重新设置 key,并且指定过期时间
this.stringRedisTemplate.opsForValue().set(key, String.valueOf(Instant.now().toEpochMilli()), expire);
}
}
使用原生的 SET KEEPTTL 命令
Redis 4 以后对于 SET
命令新增了一个选项 KEEPTTL
,它的作用就是在对 KEY 进行操作的时候,保留其过期时间(TTL)。
SET key value [NX | XX] [GET] [EX seconds | PX milliseconds |
EXAT unix-time-seconds | PXAT unix-time-milliseconds | KEEPTTL]
Spring Data Redis 的 RedisTemplate
API 并未提供 KEEPTTL
参数,我们需要获取到底层的 RedisConnection
连接对象来进行设置。
@Autowired
StringRedisTemplate stringRedisTemplate;
@Test
public void test() {
// session key
String key = "session::01";
// 从 ConnectionFactory 获取到连接
// 注意,一定要释放连接
try (RedisConnection connection = this.stringRedisTemplate.getConnectionFactory().getConnection()) {
// 使用原生的 SET 命令来更新 Value 值,并且设置 KEEPTTL 参数
connection.stringCommands().set(key.getBytes(), String.valueOf(Instant.now().toEpochMilli()).getBytes(),
Expiration.keepTtl(), // 设置 KEEPTTL 参数,保留 key 的过期时间
SetOption.UPSERT); // 不设置其他的命令参数了
}
}
RedisStringCommands
是 Redis SET
命令的抽象接口,这是一个很底层的 API,所以它的参数类型大都是 byte[]
,这需要我们自己进行转换。
注意: 一定要记得释放 RedisConnection
连接。