本文目录导读:

在Redis中设置数据过期是一个很常见的需求,下面我通过Python的redis-py库来演示几种不同的过期设置方式。
安装redis-py
pip install redis
基础连接
import redis # 连接Redis r = redis.Redis(host='localhost', port=6379, db=0) # 或者使用连接池 pool = redis.ConnectionPool(host='localhost', port=6379, db=0) r = redis.Redis(connection_pool=pool)
设置过期时间的几种方法
set时直接指定过期时间
# 设置key并指定过期时间为10秒
r.set('mykey', 'hello', ex=10)
# 设置key并指定过期时间为指定的时间点(UNIX时间戳)
import datetime
expire_at = datetime.datetime.now() + datetime.timedelta(minutes=5)
r.set('mykey', 'hello', exat=int(expire_at.timestamp()))
# 设置key并指定过期时间为毫秒
r.set('mykey', 'hello', px=10000) # 10000毫秒 = 10秒
# 设置key并指定过期时间为毫秒级别的时间戳
r.set('mykey', 'hello', pxat=int(datetime.datetime.now().timestamp() * 1000) + 10000)
设置后单独设置过期时间
# 先设置值
r.set('mykey', 'hello')
# 然后设置过期时间(秒)
r.expire('mykey', 10) # 10秒后过期
# 或者设置过期时间(毫秒)
r.pexpire('mykey', 10000) # 10000毫秒后过期
# 设置指定时间过期(UNIX时间戳)
import time
r.expireat('mykey', int(time.time()) + 10) # 10秒后过期
# 毫秒级别的时间戳
r.pexpireat('mykey', int(time.time() * 1000) + 10000)
使用setex命令
# setex: 设置值并指定过期时间(秒)
r.setex('mykey', 10, 'hello') # 10秒后过期
# psetex: 设置值并指定过期时间(毫秒)
r.psetex('mykey', 10000, 'hello') # 10000毫秒后过期
完整示例代码
import redis
import time
from datetime import datetime, timedelta
# 连接Redis
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
def demo_basic_expire():
"""基础过期示例"""
print("=== 基础过期示例 ===")
# 方法1: set时设置过期时间
r.set('user:1', 'Alice', ex=5) # 5秒后过期
print(f"设置user:1=Alice,5秒后过期")
# 立即获取
print(f"立即获取: {r.get('user:1')}")
# 等待3秒后获取
time.sleep(3)
print(f"3秒后获取: {r.get('user:1')}")
# 再等待3秒后获取(总共6秒,已过期)
time.sleep(3)
print(f"6秒后获取: {r.get('user:1')}")
def demo_expire_with_update():
"""更新过期时间示例"""
print("\n=== 更新过期时间示例 ===")
r.set('session:abc123', 'user_data')
r.expire('session:abc123', 30) # 初始设置30秒过期
# 查看剩余过期时间(秒)
ttl = r.ttl('session:abc123')
print(f"初始过期时间: {ttl}秒")
# 更新为10秒后过期
r.expire('session:abc123', 10)
ttl = r.ttl('session:abc123')
print(f"更新后过期时间: {ttl}秒")
def demo_remove_expire():
"""移除过期时间示例"""
print("\n=== 移除过期时间示例 ===")
r.set('temp:data', 'temporary', ex=60)
print(f"设置过期时间后的TTL: {r.ttl('temp:data')}")
# 移除过期时间
r.persist('temp:data')
print(f"移除过期时间后的TTL: {r.ttl('temp:data')}") # -1表示永不过期
def demo_check_expire_status():
"""检查过期状态示例"""
print("\n=== 检查过期状态示例 ===")
r.set('status:test', 'check')
# TTL: 返回剩余过期时间(秒),-1表示永不过期,-2表示key不存在
print(f"没有设置过期时间的TTL: {r.ttl('status:test')}")
# PTTL: 返回剩余过期时间(毫秒)
print(f"没有设置过期时间的PTTL: {r.pttl('status:test')}")
# 设置过期时间
r.expire('status:test', 3600)
print(f"设置1小时后过期的TTL: {r.ttl('status:test')}")
# 删除key
r.delete('status:test')
print(f"删除后的TTL: {r.ttl('status:test')}")
def demo_hash_with_expire():
"""哈希类型设置过期时间示例"""
print("\n=== 哈希类型过期示例 ===")
# 设置hash
r.hset('hash:user:1001', mapping={
'name': 'Bob',
'age': '25',
'city': 'Beijing'
})
# 对整个hash设置过期时间
r.expire('hash:user:1001', 60)
print(f"Hash过期时间: {r.ttl('hash:user:1001')}秒")
# 注意:不能对hash中的单个字段设置过期时间
def demo_list_with_expire():
"""列表类型设置过期时间示例"""
print("\n=== 列表类型过期示例 ===")
# 设置列表
r.rpush('list:queue', 'task1', 'task2', 'task3')
# 对整个列表设置过期时间
r.expire('list:queue', 30)
print(f"列表过期时间: {r.ttl('list:queue')}秒")
# 更实用的业务场景示例
def demo_session_management():
"""会话管理示例"""
print("\n=== 会话管理示例 ===")
def create_session(user_id, token):
"""创建会话,30分钟过期"""
session_key = f"session:{token}"
session_data = {
'user_id': user_id,
'login_time': datetime.now().isoformat(),
'ip': '192.168.1.1'
}
# 设置会话数据,30分钟过期
r.hset(session_key, mapping=session_data)
r.expire(session_key, 1800) # 30分钟
print(f"会话 {token} 创建成功,30分钟后过期")
def validate_session(token):
"""验证会话是否有效"""
session_key = f"session:{token}"
if r.exists(session_key):
# 会话有效,刷新过期时间(滑动过期)
r.expire(session_key, 1800) # 重新设置为30分钟
print(f"会话 {token} 有效,已刷新过期时间")
return True
else:
print(f"会话 {token} 已过期或不存在")
return False
# 测试
create_session('user_001', 'token_abc123')
time.sleep(2)
validate_session('token_abc123')
time.sleep(2)
# 删除会话模拟退出登录
r.delete('session:token_abc123')
validate_session('token_abc123')
def demo_rate_limiting():
"""速率限制示例"""
print("\n=== 速率限制示例 ===")
def check_rate_limit(user_id, limit=5, window=60):
"""
速率限制检查
limit: 在window秒内允许的最大请求数
window: 时间窗口(秒)
"""
key = f"ratelimit:{user_id}"
# 获取当前计数
current = r.get(key)
if current is None:
# 第一次请求,设置计数为1,过期时间为window秒
r.setex(key, window, 1)
return True, 1, limit
elif int(current) < limit:
# 未超过限制,增加计数
r.incr(key)
return True, int(current) + 1, limit
else:
# 超过限制
return False, int(current), limit
# 测试速率限制
user = 'user_002'
for i in range(7):
allowed, count, limit = check_rate_limit(user, limit=5, window=10)
print(f"请求 {i+1}: {'允许' if allowed else '拒绝'} (当前: {count}/{limit})")
time.sleep(0.5)
if __name__ == "__main__":
try:
# 运行所有示例
demo_basic_expire()
demo_expire_with_update()
demo_remove_expire()
demo_check_expire_status()
demo_hash_with_expire()
demo_list_with_expire()
demo_session_management()
demo_rate_limiting()
except redis.exceptions.ConnectionError as e:
print(f"Redis连接失败: {e}")
print("请确保Redis服务已启动")
重要注意事项
# 1. 过期时间的精度问题
# 使用TTL(秒)或PTTL(毫秒),注意选择合适的精度
# 2. 过期时间不能嵌套
# 对已设置过期的key再次设置值,需要重新设置过期时间
r.set('key1', 'value1', ex=10)
r.set('key1', 'value2') # 这会移除原来的过期时间!
# 正确做法:
r.set('key1', 'value2', ex=10) # 同时设置值和过期时间
# 3. 批量操作不支持单独设置过期时间
# MSET不支持过期时间,需要逐个设置
pipeline = r.pipeline()
pipeline.set('key1', 'value1', ex=10)
pipeline.set('key2', 'value2', ex=20)
pipeline.execute()
# 4. 检查过期时间
ttl = r.ttl('mykey') # -1: 永不过期,-2: key不存在,>=0: 剩余秒数
# 5. 删除key会同时删除过期时间
r.delete('mykey') # 删除key及其过期时间
最佳实践建议
- 选择合适的过期时间单位:根据业务需求选择秒或毫秒
- 设置合理的过期时间:避免过短导致频繁重建,或过长占用内存
- 使用Pipeline批量操作:高效处理多个key的过期设置
- 监控TTL变化:定期检查关键key的过期状态
- 处理过期事件:使用Redis的键空间通知(keyspace notifications)来处理过期事件
这些示例涵盖了Redis中设置过期时间的主要场景,你可以根据实际业务需求选择合适的方案。