酒店预订系统的核心不是功能堆砌,而是数据关系是否能真实反映业务流转——比如一个房间在某天被预订后,必须同时阻断其他订单对该房型+日期的重复占用,这靠外键约束不够,得靠唯一索引+应用层校验双保险。
客房与房型要分离设计,别把房型信息硬编码进 rooms
表
常见错误是把
room_type(如“豪华大床房”)、
price_per_night直接存在
rooms表里,导致调价时要批量更新、新增房型要改表结构。正确做法是拆出
room_types表,并用外键关联:
CREATE TABLE room_types (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
base_price DECIMAL(10,2) NOT NULL,
capacity TINYINT DEFAULT 2,
description TEXT
);
<p>CREATE TABLE rooms (
id INT PRIMARY KEY AUTO_INCREMENT,
room_number VARCHAR(10) NOT NULL UNIQUE,
type_id INT NOT NULL,
status ENUM('available', 'cleaning', 'maintenance', 'occupied') DEFAULT 'available',
FOREIGN KEY (type_id) REFERENCES room_types(id)
);
room_number加
UNIQUE约束,避免人工录入重复房号 别在
rooms表里存实时价格——价格随季节/活动浮动,应走独立的
room_pricing表(含
start_date/
end_date)
status用
ENUM而非字符串,减少存储和误输入风险
预订记录必须绑定具体房间,且日期范围不可重叠
很多设计只记
check_in和
check_out,却没强制关联到某个
room_id,导致无法精确控制“同一房间同一天只能有一个有效订单”。关键在
bookings表结构和唯一约束:
CREATE TABLE bookings (
id INT PRIMARY KEY AUTO_INCREMENT,
room_id INT NOT NULL,
guest_name VARCHAR(100) NOT NULL,
check_in DATE NOT NULL,
check_out DATE NOT NULL,
status ENUM('confirmed', 'cancelled', 'checked_in', 'checked_out') DEFAULT 'confirmed',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (room_id) REFERENCES rooms(id),
CHECK (check_out > check_in)
);
<p>-- 阻止同一房间在时间上有交集的预订
CREATE UNIQUE INDEX idx_room_date_overlap
ON bookings (room_id, check_in, check_out);
仅靠这个索引还不够——MySQL 的 UNIQUE索引不能自动检测区间重叠(比如 A:2024-05-01~05-03,B:2024-05-02~05-04),它只对三字段组合值唯一。真要防重叠,得在应用层查
SELECT 1 FROM bookings WHERE room_id = ? AND check_in ?
status字段必须,否则无法区分“已取消但占着日期”的脏数据 别省略
CHECK (check_out > check_in),防止插入逻辑错误日期
用户和订单解耦,避免用 users
表直接存客人证件信息
酒店常需为非注册用户(如电话预订)下单,若把身份证号、手机号全塞进
users表,会导致大量空值或滥用主账号。更合理的是分层:
users表只管登录凭证(
password_hash、
is_staff)
guests表存真实入住人信息(
id_card、
phone、
real_name),可被多个订单复用
bookings表加
guest_id外键,指向
guests.id;同时保留
created_by_user_id(可为空),表示谁下的单
这样既支持散客快速下单,又保留会员积分、历史订单归因能力。
别忽略凌晨 0 点的时间精度问题
MySQL 的
DATE类型会丢掉时间部分,导致
check_in = '2024-05-01'实际含义模糊——是 5 月 1 日 00:00 还是 12:00?预订系统必须明确: 所有日期字段统一用
DATETIME,并约定:
check_in指入住日 14:00 后(标准入住时间),
check_out指离店日 12:00 前(标准退房时间) 查询“某日可用房间”时,条件写成:
WHERE ? NOT BETWEEN check_in AND check_out,注意
BETWEEN是闭区间,得配合业务规则调整边界 应用层入库前,把用户选的“入住日期”自动转为当天 14:00 的
DATETIME,别依赖前端传时间
时间粒度错一层,库存就可能超卖。这个细节在压测时最容易暴露,但设计阶段就该定死。
