mysql搭建酒店预订系统数据库结构设计

来源:这里教程网 时间:2026-02-28 20:41:58 作者:

酒店预订系统的核心不是功能堆砌,而是数据关系是否能真实反映业务流转——比如一个房间在某天被预订后,必须同时阻断其他订单对该房型+日期的重复占用,这靠外键约束不够,得靠唯一索引+应用层校验双保险。

客房与房型要分离设计,别把房型信息硬编码进
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
表只管登录凭证(
email
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
,别依赖前端传时间

时间粒度错一层,库存就可能超卖。这个细节在压测时最容易暴露,但设计阶段就该定死。

相关推荐