sql 使用触发器防止重复预订

sql prevent double booking with trigger

我无意中为酒店预订构建了一个数据库 table。

在我的预订数据库中,有一个预订 start_datetime 和 end_datetime 属性来指示预订期间,我试图通过触发器语句来防止重复预订,但我确信这种方法会容易受到竞争条件的影响。

在这种情况下如何防止竞争条件?

触发器:

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 (
            ( new.start_datetime <= existing.start_datetime AND existing.start_datetime < new.end_datetime )
            OR ( new.start_datetime < existing.end_datetime AND existing.end_datetime <= new.end_datetime )
            OR ( existing.start_datetime <= new.start_datetime AND new.start_datetime < end_datetime )
            OR ( existing.start_datetime < new.end_datetime AND new.end_datetime <= end_datetime )
        )
    );
    IF (@val) THEN
        signal SQLSTATE '45000' SET MESSAGE_TEXT = 'Double Booking Detected';
    END IF;
END

Table:

CREATE TABLE `reservation_tbl` (
    `reserv_idx` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
    `member_idx` INT(11) UNSIGNED NOT NULL,
    `room_idx` INT(11) UNSIGNED NOT NULL,
    `start_datetime` DATETIME NOT NULL,
    `end_datetime` DATETIME NOT NULL,
    `created_datetime` DATETIME NOT NULL DEFAULT current_timestamp(),
    `updated_datetime` DATETIME NULL DEFAULT NULL ON UPDATE current_timestamp(),
    `deleted_datetime` DATETIME NULL DEFAULT NULL,
    PRIMARY KEY (`reserv_idx`) USING BTREE,
);

谢谢

ps。正在使用的数据库是 MariaDB 10.3.31。

CREATE DEFINER=`admin`@`%` TRIGGER `prevent_double_booking` 
BEFORE INSERT ON `reservation_tbl` 
FOR EACH ROW 
BEGIN
    IF EXISTS ( SELECT NULL 
                FROM `reservation_tbl` AS existing
                WHERE NEW.room_idx = existing.room_idx
                  AND new.start_datetime <= existing.end_datetime 
                  AND existing.start_datetime <= new.end_datetime ) THEN
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Double Booking Detected';
    END IF;
END

如果时隙不能相邻则使用严格的不等式而不是软的。

为了防止并发进程的交叉影响,在插入前锁定table。或插入相应隔离级别的事务。