Java里怎么搞Redis的Key过期,redisjava实现那些事儿分享一下
- 问答
- 2026-01-02 10:55:14
- 1
怎么设置Key的过期时间
这很简单,就是你往Redis里存数据的时候,多带一个参数,告诉Redis这个Key活多久,根据你用的客户端不同,写法稍微有点区别。
如果你用的是老牌的Jedis(来源:Jedis GitHub文档和常见用法),大概是这样搞的:
-
直接设置带过期时间的Key:这是一步到位的方法,你想存一个Key叫“user:1001:session”,值是“logged_in”,让它300秒后自动消失,代码就一行:
jedis.setex("user:1001:session", 300, "logged_in");这里的setex就是setwithexpire的意思。 -
先设置Key,再单独给它设过期时间:有时候你可能需要先把数据存上去,过一会儿再决定它啥时候过期,这时候可以用
expire命令。jedis.set("some:temp:data", "hello world"); // ... 中间可能还有些其他逻辑 ... jedis.expire("some:temp:data", 60); // 让这个Key在60秒后过期还有一个
pexpire,单位是毫秒,更精确。 -
用SET命令的选项:新版本的Redis的SET命令本身就很强大,Jedis也支持,你可以这样写:
jedis.set("mykey", "myvalue", "NX", "EX", 300);这行代码的意思是:设置键值对,如果Key不存在才设置(NX),并且设置过期时间为300秒(EX),这在实现分布式锁之类场景时特别常用。
如果你用的是现在更流行的Lettuce(来源:Lettuce官方文档和示例),它是异步驱动的,但用同步方式写起来也很像:
redisCommands.setex("user:1001:session", 300, "logged_in");
基本思路是一样的,就是API名字可能稍有不同。
设置过期时间这块儿没啥复杂的,就是调用现成的方法。
第二部分:Key过期后,我怎么知道?(监听Key过期事件)
这才是重点和难点,你设置了一个Key 10分钟后过期,比如一个用户登录状态,你希望它过期的时候,能触发一段Java代码,比如去清理一下本地缓存,或者记录个日志,这个功能Redis本身是支持的,但需要你在Redis服务器和Java代码里都进行配置。
你得修改Redis服务器的配置(来源:Redis官方文档关于notify-keyspace-events的说明),默认情况下,Redis为了性能,是不发送这些事件通知的,你需要找到Redis的配置文件redis.conf,在里面加一行(或者修改):
notify-keyspace-events Ex
这个Ex是什么意思呢?E表示启用Keyspace事件通知,x表示监听过期事件,你也可以用A表示监听所有事件,但通常我们只关心过期的就用Ex,改完配置后,记得重启Redis服务让它生效。
在Java代码里,你要创建一个监听器(Listener)来订阅这个事件。
用Jedis来实现的话(来源:Jedis Pub/Sub示例),它是用发布订阅(Pub/Sub)模式来做的,Redis会在Key过期时,往一个特定的频道(Channel)发一条消息,你的程序需要去订阅这个频道。
大概的代码步骤是这样的:
- 创建一个JedisPubSub对象,重写它的
onMessage方法,这个方法就是收到消息时的回调函数。 - 用另一个Jedis连接(重要:不能用发命令的那个连接,因为订阅操作会阻塞线程)去订阅一个叫
__keyevent@0__:expired的频道,这里的0是数据库编号,如果你用的是默认的0号数据库,就是这个。
示例代码片段:
new Thread(() -> {
try (Jedis subscriberJedis = jedisPool.getResource()) {
subscriberJedis.subscribe(new JedisPubSub() {
@Override
public void onMessage(String channel, String message) {
// 当收到消息时,这个函数会被调用
// message参数就是那个过期的Key的名字!
System.out.println("Key过期了:" + message + ", 频道: " + channel);
// 这里就可以写你的业务逻辑了,比如根据Key的前缀判断是什么数据,然后进行清理等操作。
if (message.startsWith("user:")) {
System.out.println("清理用户相关数据...");
}
}
}, "__keyevent@0__:expired"); // 订阅的频道
}
}).start();
注意,订阅操作是阻塞的,所以通常要放在一个单独的线程里跑。
用Lettuce的话(来源:Lettuce高级特性文档),它本身是异步的,实现起来更自然一些,Lettuce提供了反应式的监听方式:
RedisClient redisClient = RedisClient.create("redis://localhost");
StatefulRedisConnection<String, String> connection = redisClient.connect();
// 创建反应式接口
RedisReactiveCommands<String, String> reactive = connection.reactive();
// 监听过期事件频道
reactive.observeChannels(ChannelMessage.of("__keyevent@0__:expired"))
.subscribe(message -> {
String expiredKey = message.getMessage();
System.out.println("监听到Key过期: " + expiredKey);
// ... 处理逻辑 ...
});
Lettuce的这种写法利用了反应式流,看起来更现代,也更适合处理高并发的消息。
需要注意的坑:
- 事件不是百分百可靠:Redis的过期事件通知不是绝对可靠的,它只在Key被真正删除的那一刻发出通知,如果Redis服务器压力很大,或者过期Key太多,可能会导致通知有延迟甚至丢失,所以你的业务逻辑不能完全依赖这个通知,它更适合做一些辅助性的清理工作,不能用于要求强一致性的核心流程。
- 性能开销:开启键空间通知会对Redis服务器的性能有一点点影响,因为要多做一些事情。
- 连接管理:用Jedis时,负责订阅的连接要管理好,确保异常情况下能重连。
在Java里搞Redis的Key过期,设置时间很简单;想监听过期事件就得费点劲,需要配Redis服务器,然后在代码里写监听器去订阅特定频道,用Jedis和Lettuce都能实现,根据你的项目喜好和兼容性来选就行。

本文由水靖荷于2026-01-02发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://haoid.cn/wenda/73036.html
