Java Redis过期案例如何设置:从入门到实战的权威指南
📚 目录导读
Redis过期机制核心原理
Redis作为高性能内存数据库,过期键(Expire Key) 是其核心功能之一,Redis支持为每个键设置生存时间(TTL,Time To Live),当键过期后,Redis会通过惰性删除(访问时检查)与定期删除(每100ms随机抽查)两种策略结合自动清理。

关键点:过期时间设置可精确到秒或毫秒,且过期后键立即失效,但内存释放存在短暂延迟(取决于删除策略的触发时机)。
Java操作Redis过期时间的三种主流方式
1 使用Jedis(原生客户端)
Jedis jedis = new Jedis("localhost", 6379);
// 设置键值 + 过期时间(秒)
jedis.setex("session:user:1001", 3600, "active");
// 或单独设置过期时间
jedis.set("temp:code", "123456");
jedis.expire("temp:code", 300); // 5分钟
特点:底层直接调用Redis命令,性能极高,适合对延迟敏感的场景。
2 使用Spring Data Redis(推荐企业级)
@Autowired
private StringRedisTemplate redisTemplate;
// 方式1:绑定操作
redisTemplate.opsForValue().set("captcha:login", "ABC123", 5, TimeUnit.MINUTES);
// 方式2:单独设置
redisTemplate.opsForValue().set("lock:order", "occupied");
redisTemplate.expire("lock:order", 10, TimeUnit.SECONDS);
特点:支持序列化、事务与更丰富的API,推荐用于Spring Boot项目。
3 使用Redisson(分布式场景)
Config config = new Config();
config.useSingleServer().setAddress("redis://localhost:6379");
RedissonClient redisson = Redisson.create(config);
RBucket<String> bucket = redisson.getBucket("rate:limit:user:101");
bucket.set("ok", 60, TimeUnit.SECONDS); // 60秒限流
特点:天然支持分布式锁、延迟队列等高级特性,适合微服务集群。
经典案例:缓存失效与自动清理
🎯 案例1:验证码自动过期(最常用)
需求:用户注册时发送短信验证码,5分钟后失效。
public void sendSmsCode(String phone) {
String code = generateCode(); // 6位随机数
// 设置过期时间5分钟
redisTemplate.opsForValue().set("sms:code:" + phone, code, 300, TimeUnit.SECONDS);
// 同时记录发送次数(1小时限制5次)
redisTemplate.opsForValue().increment("sms:limit:" + phone, 1);
redisTemplate.expire("sms:limit:" + phone, 1, TimeUnit.HOURS);
}
效果:用户5分钟内未输入,Redis自动删除该键,后端无需额外轮询清理。
🎯 案例2:热点数据缓存+主动刷新
需求:商品详情页缓存,设置3分钟过期,但若被访问则延长5分钟。
public Product getProduct(String productId) {
String key = "product:" + productId;
Product product = (Product) redisTemplate.opsForValue().get(key);
if (product == null) {
product = loadFromDB(productId);
redisTemplate.opsForValue().set(key, product, 5, TimeUnit.MINUTES);
} else {
// 访问时续期(避免热点瞬间失效导致雪崩)
redisTemplate.expire(key, 5, TimeUnit.MINUTES);
}
return product;
}
🎯 案例3:分布式锁自动释放
关键点:过期时间防止死锁。
String lockKey = "order:pay:" + orderId;
Boolean lock = redisTemplate.opsForValue().setIfAbsent(lockKey, threadId, 30, TimeUnit.SECONDS);
if (Boolean.TRUE.equals(lock)) {
try {
processPayment(orderId);
} finally {
redisTemplate.delete(lockKey); // 业务完成及时释放
}
}
注意:过期时间需大于业务执行时间,避免锁提前释放导致并发问题。
常见问题FAQ
❓ Q1:Redis过期键会立即释放内存吗?
A:不会,Redis通过惰性删除+定期删除组合,过期键有短暂内存占用(通常不超过几秒),如需立即释放,可手动执行 UNLINK key(非阻塞删除)或 DEL key(阻塞删除)。
❓ Q2:如何查看键的剩余存活时间?
A:使用Jedis:jedis.ttl("key") (返回秒数,-1表示无过期,-2表示已不存在)
Spring Data Redis:redisTemplate.getExpire("key", TimeUnit.SECONDS)
❓ Q3:设置了过期时间,但键一直没被删除怎么办?
假设场景:内存已被占满,但过期键仍存在。
原因:Redis内存淘汰策略(如allkeys-lru)优先级高于过期删除,需将淘汰策略改为volatile-ttl(优先淘汰即将过期的键),或增加内存上限maxmemory。
❓ Q4:同时设置了EXPIRE和PEXPIRE,哪个生效?
A:后设置的覆盖前设置的。EXPIRE单位为秒,PEXPIRE为毫秒,推荐统一使用更精确的毫秒级。
性能优化与最佳实践
⚡ 优化建议
-
避免过期时间过于集中
例如1000个商品同时设10分钟过期,会导致10分钟后大量键同时清理,造成CPU瞬间飙升。解决方案:加随机偏移:expire = 600 + random.nextInt(120)。 -
慎用"永不过期"键(-1)
除非数据必须常驻内存,否则设置过期时间可预防内存泄漏。 -
监控高频删除
通过Redis命令INFO查看expired_keys指标,若每秒删除数超过阈值(如1000/s),需调整删除策略或扩容。 -
键名设计规范
使用冒号分隔业务域:业务:实体:ID:字段(如cache:user:1001:profile),便于按模式批量操作和监控。
🌐 生产级配置示例(spring-boot-starter-data-redis)
spring:
redis:
host: localhost
port: 6379
timeout: 5000ms
lettuce:
pool:
max-active: 8
max-wait: -1ms
# 全局过期时间(仅对opsForValue().set无过期时间参数时生效)
time-between-eviction-runs: 100ms
三行代码掌握核心
// 1. 设置5秒过期
redisTemplate.opsForValue().set("key", "value", 5, TimeUnit.SECONDS);
// 2. 查询剩余时间
Long ttl = redisTemplate.getExpire("key");
// 3. 取消过期
redisTemplate.persist("key");
核心认知:Redis过期机制不是“立即清除”,而是“逻辑失效+延迟清理”,在Java中,合理利用过期时间可显著减少代码复杂度,避免轮询清理,配合Redisson或Spring Cache注解(
@Cacheable(value="xxx", key="#id"),可进一步简化分布式场景的缓存管理。