预订系统超时机制实现方案及相关场景问题解析
酒店预订超时机制实现方案
一、核心超时锁定实现
用Redis带TTL的键值对是行业通用方案,具体流程:
- 用户点击预订按钮后,后端生成唯一的临时锁定订单ID,将「客房ID、用户ID、锁定开始时间」作为value存入Redis,设置20分钟TTL,key命名可以用
hotel:lock:room:{room_id}:user:{user_id},方便快速查询和管理。 - 同时在数据库的客房表或锁定记录表中,同步记录
lock_user_id、lock_expire_time字段,做双重保障(避免Redis宕机导致状态丢失)。 - 释放客房的两种触发方式:
- Redis过期通知:开启Redis的
notify-keyspace-events Ex配置,后端监听__keyevent@0__:expired事件,当锁定键过期时,自动执行释放客房的逻辑(清空数据库中的锁定字段,标记客房为可预订)。 - 定时任务兜底:用定时任务(比如Quartz、XXL-Job)每隔5分钟扫描数据库中的锁定记录,清理已过期且未转正的锁定,避免Redis通知丢失的情况。
- Redis过期通知:开启Redis的
二、UI倒计时展示
前端实现倒计时的同时,必须配合后端校验:
- 用户进入预订页面时,后端返回「锁定开始时间」和「超时时长(20分钟)」,前端在本地计算剩余时间,用
setInterval每秒更新倒计时显示。 - 倒计时结束后,前端自动禁用支付按钮,提示“预订超时,请重新发起预订”。
- 关键校验:用户提交支付或确认订单时,后端必须再次检查Redis或数据库的
lock_expire_time,确认锁定未过期,防止前端篡改本地时间绕过限制。
三、第三方支付超时的冲突处理
用户跳转到Stripe/PayPal后TTL到期、客房被释放,但后续完成支付的情况,是生产环境必须处理的场景,常用方案:
1. 支付前延长锁定时长
当用户点击「去支付」跳转第三方平台前,后端主动将该锁定的TTL延长至30-45分钟(根据第三方支付的平均耗时调整),同时更新数据库的lock_expire_time。可以限制延长次数(比如最多1次),避免恶意占用客房。
2. 支付回调时的兜底校验
第三方支付平台回调后端时,按以下逻辑处理:
- 先查询该临时锁定对应的客房状态:
- 如果客房仍未被其他用户预订:直接将临时锁定转为正式订单,完成后续流程。
- 如果客房已被他人预订:立即触发退款流程(调用Stripe/PayPal的退款API),同时通过短信/站内信通知用户“客房已被他人预订,已为您全额退款,请重新选择其他客房”。
3. 增设「支付中」过渡状态
将锁定拆分为两个阶段:
- 第一阶段:填写信息阶段,20分钟锁定,此时其他用户可以看到客房“已被锁定”。
- 第二阶段:用户发起支付后,切换为「支付中」状态,设置更长的TTL(比如40分钟),此时其他用户看到客房“支付中”,无法发起预订。该状态下即使原锁定TTL到期,也不会释放客房,直到支付完成或支付超时(比如40分钟)再处理。
额外注意点
- 要处理Redis宕机的情况:此时完全依赖数据库的
lock_expire_time字段,定时任务会清理过期锁定,保证客房不会被永久占用。 - 用户主动取消预订时,后端要主动删除Redis的锁定键,并清空数据库的锁定字段,及时释放客房。
内容的提问来源于stack exchange,提问作者bornfree
相关产品推荐
相关产品推荐

