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

酒店预订系统核心是数据关系真实反映业务流转:房间与房型须分离设计,价格动态化需独立pricing表,预订必须绑定具体房间并用应用层+唯一索引防日期重叠,用户与客人信息应解耦,日期统一用DATETIME精确到小时。

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

客房与房型要分离设计,别把房型信息硬编码进 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
);

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_numberUNIQUE 约束,避免人工录

    入重复房号
  • 别在 rooms 表里存实时价格——价格随季节/活动浮动,应走独立的 room_pricing 表(含 start_date/end_date
  • statusENUM 而非字符串,减少存储和误输入风险

预订记录必须绑定具体房间,且日期范围不可重叠

很多设计只记 check_incheck_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)
);

-- 阻止同一房间在时间上有交集的预订 CREATE UNIQUE INDEX idx_room_date_overlap ON bookings (room_id, check_in, check_out);

  • 仅靠这个索引还不够——MySQL 的 UNIQUE 索引不能自动检测区间重叠(比如 A:2025-05-01~05-03,B:2025-05-02~05-04),它只对三字段组合值唯一。真要防重叠,得在应用层查 SELECT 1 FROM bookings WHERE room_id = ? AND check_in ?
  • status 字段必须,否则无法区分“已取消但占着日期”的脏数据
  • 别省略 CHECK (check_out > check_in),防止插入逻辑错误日期

用户和订单解耦,避免用 users 表直接存客人证件信息

酒店常需为非注册用户(如电话预订)下单,若把身份证号、手机号全塞进 users 表,会导致大量空值或滥用主账号。更合理的是分层:

  • users 表只管登录凭证(emailpassword_hashis_staff
  • guests 表存真实入住人信息(id_cardphonereal_name),可被多个订单复用
  • bookings 表加 guest_id 外键,指向 guests.id;同时保留 created_by_user_id(可为空),表示谁下的单

这样既支持散客快速下单,又保留会员积分、历史订单归因能力。

别忽略凌晨 0 点的时间精度问题

MySQL 的 DATE 类型会丢掉时间部分,导致 check_in = '2025-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,别依赖前端传时间

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