基于Java+Spring+MySQL的酒店预订系统并发预订流程最佳实践咨询
酒店预订流程设计与并发处理最佳实践
方案一合理性分析
方案一的流程不合理,核心问题是用户体验极差:用户需要填写信用卡这类敏感且耗时的信息后,才得知房间已被他人预订,会直接导致用户反感、流失率上升。
同时在并发场景下,多个用户可能同时选中同一房间,都完成信用卡信息填写后才触发可用性检查,此时会出现多人通过检查但实际仅能完成一个预订的情况,进一步加剧用户体验问题。因此必须将房间可用性检查环节提前到用户填写敏感支付信息之前。
方案二实用性与行业实际做法
方案二的临时锁定思路是实用且符合行业通用逻辑的,但细节上可以优化:
- 临时预订表无需关联
reservation-id(此时正式预订尚未生成),应该包含房间ID、用户ID、过期时间、锁定状态等核心字段。 - 流程调整为:用户选房→事务性检查房间(同时校验正式预订和临时锁定记录)→可用则写入临时锁定表(设置15-30分钟过期时间)→用户填写支付信息→支付成功则生成正式
reservation记录并删除临时锁定记录;支付失败/放弃则直接删除临时锁定记录。
行业通用解决方案核心逻辑
行业主流做法均基于房间临时锁定+超时自动释放模式,具体流程如下:
- 预锁定房间:用户选房后立即触发原子性检查(事务内执行),确认房间未被正式预订且未被其他用户临时锁定,若可用则写入临时锁定表,同时告知用户房间已保留N分钟,引导完成支付。
- 完成预订/释放房间:
- 用户成功支付:在事务内生成正式
reservation记录,删除对应临时锁定记录,完成整个预订流程。 - 用户支付失败/超时未操作:通过定时任务(或数据库定时事件)清理过期的临时锁定记录,自动释放房间资源。
- 用户成功支付:在事务内生成正式
Java/Spring+MySQL技术实现要点
- 事务控制:使用Spring的
@Transactional注解包裹房间检查与临时锁定写入操作,确保这两个步骤原子性,避免并发冲突。 - 并发冲突规避:在检查房间可用性时,使用MySQL的行锁语句防止超卖,例如:
该语句会在事务内锁定目标房间行,其他线程需等待当前事务完成后才能执行检查,避免多个线程同时判定房间可用。SELECT id FROM room WHERE id = ? AND NOT EXISTS (SELECT 1 FROM reservation WHERE room_id = ? AND check_in <= ? AND check_out >= ?) AND NOT EXISTS (SELECT 1 FROM temporary_lock WHERE room_id = ? AND expiration_date > NOW()) FOR UPDATE; - 定时清理任务:用Spring Task或Quartz实现定时任务,每隔5-10分钟执行一次清理:
DELETE FROM temporary_lock WHERE expiration_date < NOW(); - 临时锁定表设计:
CREATE TABLE temporary_lock ( id BIGINT PRIMARY KEY AUTO_INCREMENT, room_id BIGINT NOT NULL, user_id BIGINT NOT NULL, expiration_date DATETIME NOT NULL, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (room_id) REFERENCES room(id), FOREIGN KEY (user_id) REFERENCES user(id) );
内容的提问来源于stack exchange,提问作者mariam
相关产品推荐
相关产品推荐

