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。或插入相应隔离级别的事务。
我无意中为酒店预订构建了一个数据库 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。或插入相应隔离级别的事务。