I am stumbled on constructing a DB table for hotel reservations.
In my reservation db, there is a reservation start_datetime and end_datetime attribute to indicate booked period and I tried to prevent double booking with a trigger statemen, but I am certain that this method would be vulnerable to race condition.
How can I prevent race condition in such case?
Trigger:
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, );
Thanks
ps. The DB at play is MariaDB 10.3.31.
Advertisement
Answer
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
If the timeslots cannot be adjacent then use strict unequiations instead of soft one.
For to prevent concurrent processes cross-influence lock the table before insertion. Or insert in the transaction of according isolation level.