Redis命令:EXPIRE

Redis EXPIRE 命令详细教程

EXPIRE 用于为 Key 设置以秒为单位的过期时间(生存时间,TTL),到期后 Redis 会自动删除该 Key。它是 Redis 最常用的通用 Key 操作命令之一,广泛应用于缓存、会话管理、限流、分布式锁等场景。

本文基于 Redis 通用 Key 操作介绍 EXPIRE。Redis 命令本身不区分大小写,因此 EXPIREexpireExpire 的效果相同;文档统一使用大写形式。EXPIRE 自 Redis 1.0 起就可用。

资料合集:https://pan.quark.cn/s/10e98d308913https://pan.quark.cn/s/f56bc69c5338

一、命令概览

1. 基本语法

redis 复制代码
EXPIRE key seconds [NX | XX | GT | LT]

参数说明:

参数 说明
key 要设置过期时间的 Key
seconds 过期时间,单位为秒,必须是正整数
NX 仅当 Key 没有过期时间时才设置(Not eXists)
XX 仅当 Key 已有过期时间时才设置(eXists)
GT 仅当新 TTL 大于当前 TTL 时才设置(Greater Than),Redis 7.0+
LT 仅当新 TTL 小于当前 TTL 时才设置(Less Than),Redis 7.0+

返回值:

  • 设置成功返回 (integer) 1
  • 设置失败返回 (integer) 0(如 Key 不存在、条件不满足等)。

2. 最简单的示例

先写入一个字符串值,然后设置 10 秒过期:

redis 复制代码
SET mykey "Hello"
EXPIRE mykey 10

返回:

text 复制代码
(integer) 1

查看剩余生存时间:

redis 复制代码
TTL mykey

返回类似:

text 复制代码
(integer) 8

二、EXPIRE 的基本用法

1. 设置秒级过期时间

redis 复制代码
SET session:user:1001 "logged_in"
EXPIRE session:user:1001 1800

返回 (integer) 1,表示该会话将在 1800 秒(30 分钟)后过期。

2. 对不存在的 Key 设置过期

redis 复制代码
EXPIRE no-such-key 60

返回:

text 复制代码
(integer) 0

Key 不存在时,EXPIRE 返回 0,不会创建 Key。

3. 秒数为 0 的情况

从 Redis 2.6 开始,EXPIRE 的秒数可以为 0,此时 Key 会立即过期(相当于被删除):

redis 复制代码
SET temp "value"
EXPIRE temp 0
EXISTS temp

EXISTS temp 返回 (integer) 0

4. 负值秒数

传入负值时,Key 也会立即过期:

redis 复制代码
SET temp "value"
EXPIRE temp -1
EXISTS temp

EXISTS temp 返回 (integer) 0

三、过期时间选项(NX / XX / GT / LT)

Redis 7.0 及以上版本支持条件选项,用于更精细地控制过期时间的设置行为。

1. NX --- 仅当没有过期时间时设置

NX(Not eXists):只有当 Key 当前没有关联过期时间(即永久有效)时,才设置新的过期时间。

redis 复制代码
SET permanent-key "forever"
EXPIRE permanent-key 3600 NX

返回 (integer) 1,因为该 Key 原本没有过期时间。

如果 Key 已有过期时间:

redis 复制代码
SET temp-key "temp" EX 60
EXPIRE temp-key 3600 NX

返回 (integer) 0,因为 NX 条件不满足。

2. XX --- 仅当已有过期时间时设置

XX(eXists):只有当 Key 当前已有过期时间时,才更新为新的过期时间。

redis 复制代码
SET temp-key "temp" EX 60
EXPIRE temp-key 3600 XX

返回 (integer) 1,因为该 Key 已有过期时间,成功更新为 3600 秒。

如果 Key 是永久有效的:

redis 复制代码
SET permanent-key "forever"
EXPIRE permanent-key 3600 XX

返回 (integer) 0,因为 XX 条件不满足。

3. GT --- 仅当新 TTL 更大时设置

GT(Greater Than):只有当新的 TTL 大于当前剩余 TTL 时,才更新过期时间。Redis 7.0+ 支持。

redis 复制代码
SET mykey "value" EX 100
EXPIRE mykey 200 GT

返回 (integer) 1,因为 200 > 100,TTL 被延长。

如果新 TTL 更小:

redis 复制代码
SET mykey "value" EX 200
EXPIRE mykey 100 GT

返回 (integer) 0,因为 100 < 200GT 条件不满足。

4. LT --- 仅当新 TTL 更小时设置

LT(Less Than):只有当新的 TTL 小于当前剩余 TTL 时,才更新过期时间。Redis 7.0+ 支持。

redis 复制代码
SET mykey "value" EX 200
EXPIRE mykey 100 LT

返回 (integer) 1,因为 100 < 200,TTL 被缩短。

如果新 TTL 更大:

redis 复制代码
SET mykey "value" EX 100
EXPIRE mykey 200 LT

返回 (integer) 0,因为 200 > 100LT 条件不满足。

5. 选项组合

NXXXGTLT 不能任意组合,NXXX 互斥,GTLT 也不能与 NX 同时使用(没有当前 TTL 时无法比较大小)。

四、EXPIRE 与相关命令的区别

1. EXPIRE 与 PEXPIRE

EXPIRE 以秒为单位设置过期时间,PEXPIRE 以毫秒为单位:

redis 复制代码
EXPIRE key 10      # 10 秒后过期
PEXPIRE key 10000  # 10000 毫秒(10 秒)后过期

两者语义完全相同,只是精度不同。需要毫秒级精度时使用 PEXPIRE

2. EXPIRE 与 EXPIREAT / PEXPIREAT

EXPIRE 设置的是相对时间(从现在起多少秒后过期),EXPIREAT 设置的是绝对时间(Unix 时间戳):

redis 复制代码
EXPIRE key 3600              # 3600 秒后过期
EXPIREAT key 1735689600      # 在指定 Unix 时间戳过期
PEXPIREAT key 1735689600000  # 毫秒级时间戳

需要在指定的绝对时间点过期时使用 EXPIREAT

3. EXPIRE 与 SET ... EX

SET 命令可以通过 EX 选项在设置值的同时指定过期时间,是原子操作:

redis 复制代码
SET cache:key "value" EX 3600

等效于(但更高效且原子):

redis 复制代码
SET cache:key "value"
EXPIRE cache:key 3600

推荐优先使用 SET ... EX 形式,因为它是原子的,避免了 SET 成功但 EXPIRE 失败导致 Key 永久有效的风险。

4. EXPIRE 与 PERSIST

PERSIST 用于移除 Key 的过期时间,使其变为永久有效:

redis 复制代码
SET temp-key "value" EX 3600
PERSIST temp-key
TTL temp-key

TTL temp-key 返回 -1(永久有效)。

EXPIRE 是"添加/修改过期时间",PERSIST 是"移除过期时间"。

5. EXPIRE 与 TTL / PTTL

TTL 以秒为单位返回 Key 的剩余生存时间,PTTL 以毫秒为单位:

状态 TTL 返回值
Key 存在且有过期时间 剩余秒数(正数)
Key 存在但无过期时间 -1
Key 不存在 -2
redis 复制代码
SET mykey "value" EX 100
TTL mykey    # 返回 100 左右
PTTL mykey   # 返回 100000 左右

6. EXPIRE 与 EXPIRETIME / PEXPIRETIME

EXPIRETIME 返回 Key 过期时间对应的 Unix 时间戳(秒),Redis 7.0+ 支持:

redis 复制代码
SET mykey "value" EX 100
EXPIRETIME mykey

返回类似 (integer) 1735689600

Key 不存在或无过期时间时返回 -1-2(规则同 TTL)。

五、过期时间的刷新与更新

1. 覆盖式更新

对已有过期时间的 Key 再次执行 EXPIRE,会覆盖原有的过期时间:

redis 复制代码
SET mykey "value" EX 100
EXPIRE mykey 200
TTL mykey

TTL mykey 返回约 200,过期时间被重置。

2. SET 命令会清除过期时间

使用 SET 命令覆盖 Key 的值时,原有的过期时间会被清除,Key 变为永久有效:

redis 复制代码
SET mykey "old" EX 3600
SET mykey "new"
TTL mykey

TTL mykey 返回 -1

注意:SET ... EXSET ... PX 形式则会设置新的过期时间。

3. 其他会影响过期时间的命令

以下命令也会影响 Key 的过期时间:

命令 对过期时间的影响
SETGETSET 清除过期时间(Key 变为永久有效)
SET ... EX / PX 设置新的过期时间
INCR / DECR / INCRBY 保留原有过期时间
LPUSH / RPUSH 保留原有过期时间
HSET / HMSET 保留原有过期时间
SADD / ZADD 保留原有过期时间
RENAME 源 Key 的过期时间转移到目标 Key
COPY 默认不复制过期时间(目标 Key 永久有效)
PERSIST 移除过期时间
GETEX 可同时修改过期属性

简单来说:修改值但不覆盖整个 Key 的命令(如 INCR、LPUSH、HSET 等)不会改变过期时间;覆盖整个 Key 的命令(如 SET)会清除过期时间。

六、Redis 过期机制原理

1. 惰性过期(Passive Expiration)

当客户端访问某个 Key 时,Redis 会检查该 Key 是否已过期,如果已过期则立即删除并返回不存在。

特点:

  • 对 CPU 友好,只在访问时检查
  • 对内存不友好,已过期但未被访问的 Key 会一直占用内存

2. 定期过期(Active Expiration)

Redis 会周期性地(默认每秒 10 次)随机抽取一部分设置了过期时间的 Key 进行检查,删除已过期的 Key。

特点:

  • 限制每次检查的数量和耗时,避免阻塞
  • 不能保证所有过期 Key 都被及时删除
  • 通过随机采样逐步清理过期 Key

3. 内存淘汰(Eviction)

当 Redis 内存使用达到 maxmemory 上限时,会触发内存淘汰策略,可能删除未过期的 Key 以释放内存。

淘汰策略包括 volatile-lruallkeys-lruvolatile-lfuallkeys-lfuvolatile-randomallkeys-randomvolatile-ttlnoeviction 等。

4. 过期 Key 的复制与 AOF

  • 主从复制 :主节点删除过期 Key 后,会向所有从节点发送 DEL 命令,从节点被动删除。
  • AOF 持久化 :Key 过期被删除时,会向 AOF 文件追加一条 DEL 命令。
  • 从节点不会主动过期 Key,而是等待主节点的 DEL 命令,以保证主从数据一致性。

七、EXPIRE 与不同数据类型

EXPIRE 作用于整个 Key,而不是 Key 内部的单个元素。所有数据类型(String、Hash、List、Set、Sorted Set、Stream 等)的过期行为一致。

redis 复制代码
HSET user:1001 name "Alice" age 30
EXPIRE user:1001 3600
redis 复制代码
RPUSH queue:jobs job-a job-b job-c
EXPIRE queue:jobs 1800
redis 复制代码
SADD tags redis python java
EXPIRE tags 7200
redis 复制代码
ZADD leaderboard 100 "player1" 200 "player2"
EXPIRE leaderboard 86400

过期后整个 Key 及其所有数据都会被删除。

注意:Redis 7.4 引入了 Hash 字段级过期(HEXPIRE 等),但这是字段级别的,与 Key 级别的 EXPIRE 不同。

八、事务、Pipeline 与并发场景

1. 在事务中使用

EXPIRE 可以放入事务队列:

redis 复制代码
MULTI
SET lock:order:1001 "owner"
EXPIRE lock:order:1001 30
EXEC

EXEC 执行后返回各命令的结果。

2. 原子性与 SET ... EX

"先 SET 再 EXPIRE" 不是原子操作。如果 SET 成功后客户端崩溃或网络中断,EXPIRE 可能不会执行,导致 Key 永久有效。

推荐使用原子的 SET ... EX 形式:

redis 复制代码
SET lock:order:1001 "owner" EX 30

这保证了设置值和设置过期时间在同一个原子操作中完成。

3. EXPIRE 与分布式锁

在分布式锁场景中,EXPIRE 用于设置锁的自动释放时间,防止锁持有者崩溃后锁永远无法释放:

redis 复制代码
SET lock:resource "client-id" NX EX 30

这里 NX 保证只有一个客户端能获取锁,EX 30 保证 30 秒后锁自动释放。

仅使用 EXPIRE 来续期锁(锁续期/看门狗机制)时,应使用 XX 选项确保锁仍然存在:

redis 复制代码
EXPIRE lock:resource 30 XX

如果返回 0,说明锁已经不存在(可能已过期或被释放)。

4. Pipeline 批量设置

需要为大量 Key 设置过期时间时,可以使用 Pipeline 批量发送 EXPIRE 命令,减少网络往返。

九、在常见客户端中的使用方式

1. redis-cli

bash 复制代码
redis-cli SET session:user "active"
redis-cli EXPIRE session:user 1800
redis-cli TTL session:user
redis-cli PERSIST session:user

2. Python(redis-py)

python 复制代码
import redis

client = redis.Redis(host="localhost", port=6379, decode_responses=True)
client.set("session:user", "active")

# 设置 1800 秒过期
client.expire("session:user", 1800)

# 查看剩余 TTL
ttl = client.ttl("session:user")
print(ttl)  # 1800 左右

# 移除过期时间
client.persist("session:user")
print(client.ttl("session:user"))  # -1

3. Node.js(node-redis)

javascript 复制代码
import { createClient } from "redis";

const client = createClient();
await client.connect();

await client.set("session:user", "active");

// 设置 1800 秒过期
await client.expire("session:user", 1800);

// 查看剩余 TTL
const ttl = await client.ttl("session:user");
console.log(ttl); // 1800 左右

// 移除过期时间
await client.persist("session:user");
console.log(await client.ttl("session:user")); // -1

await client.quit();

4. Java(Jedis)

java 复制代码
try (Jedis jedis = new Jedis("localhost", 6379)) {
    jedis.set("session:user", "active");

    // 设置 1800 秒过期
    long result = jedis.expire("session:user", 1800);
    System.out.println(result); // 1

    // 查看剩余 TTL
    long ttl = jedis.ttl("session:user");
    System.out.println(ttl); // 1800 左右

    // 移除过期时间
    jedis.persist("session:user");
    System.out.println(jedis.ttl("session:user")); // -1
}

十、典型使用场景

1. 缓存管理

为缓存数据设置过期时间,自动失效并刷新:

redis 复制代码
SET cache:product:1001 "{...json...}" EX 3600

缓存数据在 1 小时后自动过期,下次访问时重新从数据库加载。

2. 会话管理

用户登录会话设置过期时间,超时自动登出:

redis 复制代码
SET session:abc123 "user:1001" EX 1800

用户每次操作后续期(刷新 TTL):

redis 复制代码
EXPIRE session:abc123 1800

3. 分布式锁

为锁设置过期时间,防止死锁:

redis 复制代码
SET lock:order:1001 "client-uuid" NX EX 30

锁的持有者崩溃后,30 秒后锁自动释放。

4. 限流计数

滑动窗口限流中,为计数器设置过期时间:

redis 复制代码
INCR rate:limit:user:1001
EXPIRE rate:limit:user:1001 60

每分钟重置一次计数。

5. 一次性令牌

验证码、重置密码链接等一次性数据设置短过期时间:

redis 复制代码
SET sms:code:13800138000 "123456" EX 300

5 分钟后验证码自动失效。

6. 延迟任务

利用 Key 过期事件(keyspace notification)实现简单的延迟任务:

redis 复制代码
SET delay:task:1001 "data" EX 3600

配合 notify-keyspace-events Ex 配置,订阅过期事件来触发延迟任务。

十一、性能与使用建议

  1. 时间复杂度:O(1)。

  2. EXPIRE 是写命令(ACL 类别为 @keyspace@write@fast),会修改 Key 的元数据。

  3. 优先使用 SET key value EX seconds 而不是 SET + EXPIRE 两步操作,避免 SET 成功但 EXPIRE 失败导致 Key 永久有效。

  4. 大量 Key 同时过期可能导致 Redis 瞬间压力增大(缓存雪崩)。可以在过期时间上加入随机偏移,打散过期时间:

    redis 复制代码
    EXPIRE cache:key 3600
    # 改为 3600 ± 300 秒的随机值,避免同时过期
  5. 不要对大 Key 使用过短的过期时间(如频繁创建和删除大集合 Key),因为删除大 Key 可能阻塞 Redis。

  6. 需要精确控制过期时间点时使用 EXPIREAT,需要毫秒精度时使用 PEXPIRE/PEXPIREAT

  7. Redis 7.0+ 的条件选项(NXXXGTLT)可以在很多场景下替代"先 TTL 判断再 EXPIRE"的非原子流程,使用更安全。

  8. 集群模式下,EXPIRE 作用于单个 Key,不受哈希槽限制;涉及多个 Key 的操作需注意槽位分布。

十二、常见问题排查

问题 1:EXPIRE 返回 1 但 Key 没有过期

确认以下几点:

  1. 使用 TTL key 确认剩余时间是否正确。
  2. 是否在 EXPIRE 之后又执行了 SET 等会清除过期时间的命令。
  3. Key 是否被 PERSIST 移除了过期时间。
  4. 是否是从节点读取(从节点不会主动过期 Key,等待主节点同步)。
redis 复制代码
TTL mykey
PTTL mykey
EXPIRETIME mykey

问题 2:Key 提前过期了

可能的原因:

  1. 内存达到 maxmemory 上限,触发了内存淘汰策略,Key 被提前淘汰。
  2. 有其他客户端调用了 DELSET(覆盖)等命令删除或覆盖了 Key。
  3. EXPIRE 的秒数计算有误(注意是秒不是毫秒)。
  4. 系统时间被修改(Redis 使用系统时间计算过期,时间跳转会影响过期判断)。

问题 3:EXPIRE 总是返回 0

可能的原因:

  1. Key 不存在(先 EXISTS 确认)。
  2. 使用了条件选项(NX/XX/GT/LT)但条件不满足。
  3. 传入的秒数格式不正确(必须是整数)。

问题 4:过期的 Key 还占用内存

Redis 的过期删除是惰性 + 定期采样的混合策略,已过期但未被访问也未被采样到的 Key 会暂时留在内存中。这是正常现象,内存不会无限增长,因为定期采样会逐步清理。

如果内存压力大,可以:

  • 调整 hz 参数提高定期检查频率(会增加 CPU 消耗)。
  • 启用内存淘汰策略。
  • 主动使用 SCAN + EXPIRE/DEL 批量清理。

问题 5:Redis 重启后过期时间丢失

如果使用 RDB 持久化,Key 的过期信息会保存在 RDB 文件中,重启后恢复。如果使用 AOF 持久化,EXPIRE 命令会被追加到 AOF 文件中,重启后通过重放恢复。

注意:如果 Key 在持久化之前已经过期,RDB/AOF 中不会包含该 Key。

十三、完整练习

下面的示例演示从设置过期时间、验证 TTL、条件选项、更新过期时间,到与 SETPERSISTTTL 等命令配合使用的完整流程:

redis 复制代码
DEL demo:key
DEL demo:perm
DEL demo:renew

# 基本用法:设置 60 秒过期
SET demo:key "hello"
EXPIRE demo:key 60
TTL demo:key

# 对不存在的 Key 设置过期
EXPIRE demo:noexist 60

# SET 会清除过期时间
SET demo:key "new value"
TTL demo:key

# 使用 SET ... EX 原子设置
SET demo:key "with ttl" EX 120
TTL demo:key

# PERSIST 移除过期时间
PERSIST demo:key
TTL demo:key

# 条件选项示例(需要 Redis 7.0+)
# NX:仅当无过期时间时设置
SET demo:perm "permanent"
EXPIRE demo:perm 300 NX
TTL demo:perm
EXPIRE demo:perm 600 NX   # 返回 0,因为已有过期时间

# XX:仅当有过期时间时更新
EXPIRE demo:perm 600 XX
TTL demo:perm

# 续期场景模拟
SET demo:renew "session" EX 30
TTL demo:renew
EXPIRE demo:renew 60 XX   # 续期到 60 秒
TTL demo:renew

# Hash 类型的过期
HSET demo:hash name "Alice" age 30
EXPIRE demo:hash 3600
TTL demo:hash

# 验证过期后 Key 不存在
# (先设置极短过期时间,等待后验证)
SET demo:short "gone" EX 1
# 等待 1 秒后执行:
# EXISTS demo:short
# TTL demo:short

预期结果:

  • EXPIRE demo:key 60 返回 (integer) 1TTL demo:key 返回约 60
  • EXPIRE demo:noexist 60 返回 (integer) 0
  • SET demo:key "new value"TTL demo:key 返回 -1(过期时间被清除)。
  • SET demo:key "with ttl" EX 120TTL demo:key 返回约 120
  • PERSIST demo:key 返回 1TTL demo:key 返回 -1
  • EXPIRE demo:perm 300 NX 返回 1,第二次 NX 返回 0
  • EXPIRE demo:perm 600 XX 返回 1TTL 返回约 600
  • EXPIRE demo:renew 60 XX 返回 1,TTL 从约 30 变为约 60。
  • EXPIRE demo:hash 3600 返回 1TTL demo:hash 返回约 3600
  • 过期后 EXISTS demo:short 返回 (integer) 0

十四、命令速查表

需求 命令 精度
设置秒级过期时间 EXPIRE key seconds
设置毫秒级过期时间 PEXPIRE key milliseconds 毫秒
按 Unix 时间戳设置过期(秒) EXPIREAT key timestamp
按 Unix 时间戳设置过期(毫秒) PEXPIREAT key milliseconds-timestamp 毫秒
获取剩余生存时间(秒) TTL key
获取剩余生存时间(毫秒) PTTL key 毫秒
获取过期时间戳(秒) EXPIRETIME key
获取过期时间戳(毫秒) PEXPIRETIME key 毫秒
移除过期时间(永久有效) PERSIST key ---
原子设置值和过期时间 SET key value EX seconds
仅当无过期时间时设置 EXPIRE key seconds NX
仅当有过期时间时更新 EXPIRE key seconds XX
仅当新 TTL 更大时更新 EXPIRE key seconds GT
仅当新 TTL 更小时更新 EXPIRE key seconds LT

总结

EXPIRE 的核心作用是为 Key 设置以秒为单位的过期时间,到期后 Redis 自动删除该 Key:

redis 复制代码
EXPIRE key seconds [NX | XX | GT | LT]

使用时重点注意五点:

  • 优先使用 SET key value EX seconds 的原子形式,避免 SET 成功但 EXPIRE 失败导致 Key 永久有效。
  • SET 等覆盖 Key 的命令会清除原有过期时间;INCRLPUSHHSET 等修改内部数据的命令则保留过期时间。
  • Redis 通过惰性过期 + 定期采样的方式删除过期 Key,不能保证过期后立即释放内存。
  • Redis 7.0+ 支持 NXXXGTLT 条件选项,可以原子地实现"仅当无过期时设置"、"续期"等场景。
  • 大量 Key 同时过期可能引发缓存雪崩,建议在过期时间上加入随机偏移以打散过期峰值。
相关推荐
InfinitePlus33 分钟前
redis数据持久化
数据库·redis·缓存
Baron X3 小时前
Redis 7.0.9 完整部署指南
数据库·redis
夕除10 小时前
redis--009
redis·后端
梦Arrebol20 小时前
Redis 内容及相关实验
数据库·redis
只爱喝胡辣汤1 天前
Redis Intset(整数集合)技术文档
redis
01传说1 天前
redis开机自启脚本
数据库·redis·缓存
只爱喝胡辣汤1 天前
Redis SDS(Simple Dynamic String)技术文档
redis
只爱喝胡辣汤1 天前
Redis Dict(字典/哈希表)技术文档
redis
就叫_这个吧1 天前
RabbitMQ+elasticsearch+Redis,实现新增内容并异步到es中,是否消费成功检测
redis·elasticsearch·rabbitmq