You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MariaDB酒店预订场景如何解决触发器防重复预订的竞态条件问题

MariaDB 10.3环境下酒店预订系统避免重复预约竞态的解决方案

问题根源

当前触发器存在竞态的核心原因是:BEFORE INSERT触发器中的SELECT默认是快照读,并发事务同时执行查询时,会互相看不到对方未提交的插入记录,最终导致两个冲突的预约都插入成功。

修复步骤

1. 补充必要联合索引

为了避免后续加锁操作锁全表,同时提升查询效率,首先给房间ID、时间、软删除字段加联合索引,可在线执行不锁表:

ALTER TABLE `reservation_tbl` 
ADD INDEX `idx_room_time_delete` (`room_idx`, `start_datetime`, `end_datetime`, `deleted_datetime`),
ALGORITHM=INPLACE, LOCK=NONE;

2. 修正触发器逻辑

核心修改三点:

  • 简化时间重叠判断逻辑,通用规则不易出歧义
  • 增加软删除过滤,排除已取消的预约记录
  • 查询加FOR UPDATE转为当前读,触发InnoDB的行锁+间隙锁,阻塞并发的同房间预约查询,避免幻读
CREATE DEFINER=`admin`@`%` TRIGGER `prevent_double_booking` BEFORE INSERT ON `reservation_tbl` FOR EACH ROW BEGIN
    SET @val = EXISTS (
        SELECT NULL FROM `reservation_tbl` AS existing
        WHERE NEW.room_idx = existing.room_idx
        -- 过滤已取消的预约
        AND existing.deleted_datetime IS NULL
        -- 半开区间时间重叠判断:符合酒店预订「前一个订单12点退房、后一个订单12点可入住」的常规规则,需调整边界可修改比较符
        AND NEW.start_datetime < existing.end_datetime
        AND existing.start_datetime < NEW.end_datetime
        -- 转为当前读加排他锁,阻塞同房间的并发查询
        FOR UPDATE
    );
    IF (@val) THEN
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Double Booking Detected';
    END IF;
END

3. 补充UPDATE场景的校验逻辑

如果业务支持修改预约的时间、房间号,需要同步新增BEFORE UPDATE触发器,逻辑和上述INSERT触发器完全一致,避免修改预约信息时产生冲突。

注意事项

  • 保持MariaDB默认的**可重复读(REPEATABLE READ)**隔离级别即可,该级别下的间隙锁可以彻底避免同房间同时段插入的幻读问题
  • 若有批量插入预约的需求,需要确保批量操作在同一个事务内执行,避免部分插入成功部分失败的不一致问题
  • 单库并发量极高的场景,可配合应用层的房间维度分布式锁做双重校验,进一步降低数据库层面的锁冲突概率

内容的提问来源于stack exchange,提问作者IChung

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 21:09:03