使用Redis的key过期机制实现订单自动过期是最简单高效的方式。具体步骤:1. 将订单信息存入Redis时,使用SETEX命令设置过期时间,例如SETEX order:123 3600 '{"userId":1,"amount":100}',表示订单ID为123的订单3600秒后自动过期。2. 设置过期时间时,根据业务计算,例如下单后30分钟过期:expire_time = 30 * 60。3. 订单过期后处理:监听Redis的keyspace notifications(配置notify-keyspace-events Ex),在__keyevent@0__:expired频道订阅过期事件,当key过期时收到通知,触发回调处理如释放库存、发送通知等。代码示例:redisTemplate.expire("order:" + orderId, 30, TimeUnit.MINUTES); 监听器:@RedisKeyspaceEvent(keyspace = KeyspaceEvent.Expiration)
方案一:Redis Key TTL过期机制
在订单创建时,将订单数据以Key-Value形式存入Redis,并设置TTL过期时间。例如:redis.setex('order:' + orderId, 1800, orderData),1800秒即30分钟后自动删除订单Key。优点:无需定时任务,Redis自动处理。
订单过期回调处理
开启Redis事件通知:config set notify-keyspace-events Ex。Java中使用RedisMessageListenerContainer监听expired事件:public class RedisKeyExpirationListener { @EventListener public void handleKeyExpiration(RedisKeyspaceEvent event) { String key = event.getSource(); if(key.startsWith("order:")) { //处理过期订单,如更新数据库状态为已过期,释放锁定的商品库存 } } }
设置订单过期时间的最佳实践
订单过期时间通常设置为下单后15-60分钟,根据业务场景调整。使用StringRedisTemplate.opsForValue().set("order:" + orderId, JSON.toJSONString(order), 30, TimeUnit.MINUTES); 确保原子性,避免并发问题。
方案二:结合延迟队列
除了TTL,还可以用Redis ZSET作为延迟队列:zadd delayQueue expireTime, orderId。定时任务扫描score<当前时间的数据,处理过期订单。过期后:更新订单状态为失效,异步通知用户,解锁库存。
过期后处理流程
1. 监听Redis Key过期事件。2. 获取订单ID,从数据库查询完整订单信息。3. 更新订单状态为"已过期"。4. 释放商品库存(库存+锁定量)。5. 发送短信/推送通知用户订单已过期。6. 记录日志用于审计。
注意事项
1. 开启keyspace events可能有性能影响,生产环境评估流量。2. 过期事件是异步的,不保证顺序。3. 集群模式下需使用KeyEventMessageListenerContainer。4. 测试时用CONFIG SET notify-keyspace-events "Ex"。
FAQ
Q: Redis过期事件可靠吗?
A: 基本可靠,但重启或网络问题可能丢失事件,建议结合定时任务兜底扫描。
Q: 如何计算过期时间?
A: 订单创建时间 + 业务过期时长,如创建时间 + 30分钟。
Q: 订单数据只存Redis还是同步数据库?
A: 关键数据存Redis快照,过期时再同步更新数据库。
Q: 集群环境下怎么监听过期事件?
A: 使用Redis Sentinel或Cluster模式下的分布式监听器。