尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Python+MySQL酒店管理系统:数据库课程设计高分实现与避坑指南

发布时间:2026/9/26 18:21:51

资讯中心
01
ARTICLE

Python+MySQL酒店管理系统:数据库课程设计高分实现与避坑指南

Python+MySQL酒店管理系统:数据库课程设计高分实现与避坑指南
简介这是一份面向数据库课程设计与期末大作业的Python酒店管理系统完整项目适合有数据库或Python基础、正在准备课程设计的学生参考。项目以酒店管理业务为场景涵盖客房信息管理、入住退房、账单报表等典型功能并将代码、文档与使用教程打包在一起下载后按说明部署即可运行。压缩包共61个文件整包约8.3MB其中以18个Python源码文件、8个UI界面文件、3个SQL数据库脚本和2份PDF系统设计报告为主另附E-R图、功能结构图、XML配置与README说明文件类型覆盖源码、界面、数据库、文档多个维度目录结构清晰便于按模块查阅。代码中带有详细注释关键业务逻辑容易理解SQL脚本可导入MySQL数据库结合E-R图和设计报告能快速理清表结构、字段含义及数据关联使用教程则对运行环境、启动步骤和常见问题做了说明降低了上手门槛。目前已有281人学习下载整体完成度和规范性较好适合作为期末大作业或课程设计的高分参考与二次开发基础。1. 数据库大作业为什么都爱做酒店管理系统一个晚上能跑通的高分选题期末还剩两周数据库课设题目还没定身边十个同学里至少有三四个会告诉你做酒店管理系统。这个题目几乎是数据库大作业里的必争之地——业务不复杂三张表就能讲清楚又有完整的前台动作入住、退房、查询、结算全都落在数据库增删改查上而且网上现成的基于 python 酒店管理系统源代码和文档说明一抓一大把改一改就能交。这篇笔记按我做课设辅导的经验把整个高分项目拆开讲数据库表怎么设计、Python 业务层怎么写、文档和使用教程怎么补完以及最容易被老师问住的那些坑。适合正在做数据库课程设计、或者想用这个方向练手 python 入门的读者照着写基本能避开八成翻车现场。2. 先把数据库立住三张表的设计、建库 SQL 和 MySQL 的选型理由2.1 业务边界与三张表酒店系统为什么不需要十张表做任何课设之前先做减法。酒店管理系统听起来很大真正绕不开的核心操作只有四件事房间维护、客人登记、入住退房、查询统计。这四件事恰好覆盖数据库的增删改查又不需要碰支付、会员积分、多门店这些会让表结构爆炸的需求。对应到数据模型就是三张表。room 表管房间信息和房态guest 表管客人档案orders 表管一次入住订单用 room_id 和 guest_id 把另外两张表关联起来。这个设计天然满足第三范式订单表里只存外键不冗余客人的姓名、电话也不冗余房间的房号和价格因为这两份信息随时可以从另外两张表查出来。老师很喜欢问一句你这订单表为什么不直接存客人名字答案就是一旦客人电话改了你只改 guest 表一处订单表不会出现脏数据。这句话值得在文档和答辩里反复强调。还有一种常见设计是把房型拆成第四张表 room_type把价格和房型描述抽出去。我的建议是课设阶段不要主动拆除非你能讲清楚套房周末加价这类业务场景。刻意多拆表而不给理由反而会被追问到哑口无言。房态字段也不要存中文用 TINYINT 存 0 空闲、1 入住、2 停用查询条件干净也方便后端逻辑判断。2.2 建库建表 SQLInnoDB、utf8mb4、外键约束一次写对建库脚本是整个项目的根后面所有代码都建立在这几行 SQL 上。以下是我一般会用的 init.sql 核心部分CREATE DATABASE hotel_db DEFAULT CHARACTER SET utf8mb4; USE hotel_db; CREATE TABLE room ( room_id INT PRIMARY KEY AUTO_INCREMENT, room_no VARCHAR(10) NOT NULL UNIQUE, room_type VARCHAR(20) NOT NULL, price DECIMAL(10,2) NOT NULL, floor INT NOT NULL, status TINYINT NOT NULL DEFAULT 0, INDEX idx_room_status(status) ) ENGINEInnoDB; CREATE TABLE guest ( guest_id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL, id_card VARCHAR(18) NOT NULL UNIQUE, phone VARCHAR(20), create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB; CREATE TABLE orders ( order_id INT PRIMARY KEY AUTO_INCREMENT, room_id INT NOT NULL, guest_id INT NOT NULL, checkin_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, checkout_time DATETIME, deposit DECIMAL(10,2) NOT NULL DEFAULT 0, total_amount DECIMAL(10,2), refund DECIMAL(10,2) DEFAULT 0, status TINYINT NOT NULL DEFAULT 0, CONSTRAINT fk_order_room FOREIGN KEY (room_id) REFERENCES room(room_id), CONSTRAINT fk_order_guest FOREIGN KEY (guest_id) REFERENCES guest(guest_id), INDEX idx_order_status(status) ) ENGINEInnoDB;几个选型理由值得写进文档。表引擎必须用 InnoDB因为入住和退房是典型的事务场景MyISAM 不支持事务一旦中间步骤失败就会出现房间占用了但订单没建成的脏状态。字符集全链路指定 utf8mb4这是防止中文乱码的第一步。金额字段用 DECIMAL(10,2) 而不是 FLOAT浮点数的二进制表示会让 288 变成 287.9999。外键约束一定要建这是数据库课设的评分点后面删除房间时踩的坑也来自这里见第 5 章。表名特意用 orders 而不是 order因为 ORDER 是 MySQL 的保留字直接建表会报 1064 语法错误这是老手也容易犯的毛病。插入几条初始数据跑通系统INSERT INTO room(room_no, room_type, price, floor, status) VALUES (201, 大床房, 288.00, 2, 0), (202, 双人间, 328.00, 2, 0), (301, 大床房, 368.00, 3, 0), (302, 套房, 668.00, 3, 0);2.3 为什么选 MySQL 而不是 SQLite连接配置、可视化管理工具和评分视角直接说结论课设选 MySQL别选 SQLite。SQLite 是单文件嵌入式数据库零配置就能跑做 python 入门练习很香但拿到数据库课设里是减分项——老师问你的事务隔离级别是什么你的连接池怎么配用户权限怎么管SQLite 一个都答不上来。MySQL 是真实的服务进程有端口、有用户权限、有独立的连接配置正好把课设该有的工程感做出来。日常开发用 Navicat 连接数据库可视化地导入 init.sql、看表结构和数据比在黑框里敲命令直观得多这也是主流酒店管理系统开发里的常规操作。连接参数集中在 config.py 里答辩前换机器只改密码一个字段就行# config.py DB_CONFIG { host: 127.0.0.1, port: 3306, user: root, password: 123456, database: hotel_db, charset: utf8mb4 }这里有个细节host 建议直接写 127.0.0.1 而不是 localhost。部分环境里 pymysql 解析 localhost 会走 IPv6 的 ::1MySQL 默认只监听 127.0.0.1结果就是连接被拒这个坑第 5 章还会展开。另外如果你装的是 MySQL 8.x默认密码插件是 caching_sha2_password跑 pymysql 时会报认证插件错误解决办法也放在第 5 章。3. Python 业务层怎么写pymysql 连接、参数化查询和事务提交3.1 工程骨架配置、连接、业务、入口四层各管什么源代码如果全堆在一个 main.py 里跑得通但经不起问。我一般把项目拆成这样文件少但分层清楚hotel/ ├── init.sql # 建库建表脚本答辩前重新初始化用 ├── config.py # 数据库连接参数 ├── db_conn.py # 连接封装 ├── service.py # 入住/退房/查询等业务函数 ├── main.py # 命令行菜单入口 ├── README.md # 使用教程 └── 文档说明.docx # 需求分析 ER 图 数据字典config.py 只放连接参数db_conn.py 只负责建立连接。这样做的理由很实际答辩换到老师电脑上数据库密码大概率不一样只改 config.py 一个文件就是后悔药而连接逻辑和业务逻辑分开老师问你的代码分了几层时你能答得比绝大多数人清楚。# db_conn.py import pymysql from config import DB_CONFIG def get_conn(): # 每次调用建立独立连接课设规模下够用 return pymysql.connect(**DB_CONFIG)注意 pymysql.connect 不是线程安全的懒加载连接每次业务操作都通过 get_conn() 拿新连接用完在 finally 里关闭。这个模式简单可靠等做到第 6 章的连接池再优化现在是课程作业稳定第一。3.2 入住登记核心代码查房、写客人、建订单、改房态四步一个事务入住登记是系统里最值得写进文档的功能因为它一次演示了参数化查询、事务、外键和状态机。代码逻辑分四步查空闲房间、写客人档案、创建订单、把房间状态改成已入住。# service.py import pymysql from datetime import datetime from db_conn import get_conn def check_in(room_no, name, id_card, phone, deposit): conn get_conn() try: with conn.cursor() as cur: # 1. 查房间FOR UPDATE 在事务内锁住这行防止两人同时抢房 cur.execute( SELECT room_id, price FROM room WHERE room_no%s AND status0 FOR UPDATE, (room_no,) ) room cur.fetchone() if room is None: raise RuntimeError(f房间 {room_no} 不存在或已被占用) room_id, price room # 2. 写客人身份证号重复时复用旧档案并返回已有 guest_id cur.execute( INSERT INTO guest(name, id_card, phone) VALUES(%s, %s, %s) ON DUPLICATE KEY UPDATE guest_idLAST_INSERT_ID(guest_id), nameVALUES(name), phoneVALUES(phone), (name, id_card, phone) ) guest_id cur.lastrowid # 3. 创建未结算订单status0 cur.execute( INSERT INTO orders(room_id, guest_id, deposit, status) VALUES(%s, %s, %s, 0), (room_id, guest_id, deposit) ) # 4. 占用房间 cur.execute(UPDATE room SET status1 WHERE room_id%s, (room_id,)) conn.commit() return True except Exception as e: conn.rollback() raise e finally: conn.close()四个参数你必须懂。第一个所有 SQL 都用 %s 占位符而不是字符串拼接pymysql 会做参数转义这是防 SQL 注入的唯一正确写法老师问你怎么防注入就把这段代码指给他看。第二个ON DUPLICATE KEY UPDATE 配合 LAST_INSERT_ID是老客户复用档案的标准写法注意 guest 表的 id_card 字段建了唯一索引这条语句才生效。第三个SELECT ... FOR UPDATE 把房间行锁住事务提交前其他连接改不了这行课设答并发抢同一间房的问题就靠它。第四个四步操作共用一个事务任何一步抛异常都 rollback不会留下半截数据。3.3 退房结算按天计费、最少一晚和押金退还怎么算退房是入住的反向操作但多了一个金额计算这里最容易在边界条件上翻车。结算逻辑是查订单、算住几天、乘房价、算押金退还、改订单状态、释放房间。def check_out(order_id): conn get_conn() try: with conn.cursor() as cur: # 查出未结算订单连带房间价格 cur.execute( SELECT o.room_id, o.checkin_time, o.deposit, r.price FROM orders o JOIN room r ON o.room_idr.room_id WHERE o.order_id%s AND o.status0, (order_id,) ) order cur.fetchone() if order is None: raise RuntimeError(订单不存在或已经结算过) room_id, checkin_time, deposit, price order # 天数当天入住当天退按 1 晚算跨天按实际天数 days (datetime.now() - checkin_time).days if days 1: days 1 total round(days * float(price), 2) refund round(float(deposit) - total, 2) cur.execute( UPDATE orders SET checkout_timeNOW(), total_amount%s, refund%s, status1 WHERE order_id%s, (total, refund, order_id) ) cur.execute(UPDATE room SET status0 WHERE room_id%s, (room_id,)) conn.commit() return total, refund except Exception as e: conn.rollback() raise e finally: conn.close()这里有两个细节建议写进文档。一是天数计算用 (now - checkin_time).days 取天数差但当天入住当天退的情况 days 等于 0酒店行业惯例最少按一晚算所以加一个 if days 1 的兜底。二是 refund 可能是负数说明押金不够房费此时业务上应该补收打印提示时别写成退还押金。最后给 main.py 一个最小命令行入口让整个系统能跑起来# main.py from service import check_in, check_out def menu(): while True: print(1 入住登记 2 退房结算 3 查房态 0 退出) cmd input(请选择操作) if cmd 1: check_in(input(房间号), input(姓名), input(身份证), input(电话), float(input(押金))) elif cmd 2: total, refund check_out(int(input(订单号))) print(f房费 {total} 元押金结算 {refund} 元) elif cmd 0: break这段代码故意很简洁界面不是课设重点所有房间的增删改查函数照这个模式补全就行。能把入住、退房跑通项目的核心完成度已经 80%。4. 文档、使用教程和演示设计高分项目的一半功夫在数据库之外4.1 文档三件套需求分析、ER 图和数据字典的写法源代码只占高分项目的一半另一半是文档说明和使用教程。老师第一眼看的就是文档文档决定了项目像不像一个认真做的数据库设计。三件套分别是需求分析、ER 图、数据字典。需求分析写两页就够背景、角色、功能清单。功能清单要分必做和扩展必做四件事对应第 2 章的四项操作扩展写支持会员折扣支持换房这类开放性方向让老师看到你思考过而不是只会抄。ER 图用 draw.io 或亿图画导出 PNG 贴进文档实体就是三张表关系是 room 1 对 N orders、guest 1 对 N orders。不要画复杂的分支三张表的关系一眼讲得清才是课设的合理复杂度。数据字典是老师最喜欢翻的一页每张表一个字段表写明类型、约束和业务含义。room 表示例字段类型约束说明room_idINTPK, AUTO_INCREMENT房间主键room_noVARCHAR(10)UNIQUE, NOT NULL房号物理标识room_typeVARCHAR(20)NOT NULL房型大床房/双人间/套房priceDECIMAL(10,2)NOT NULL门市价按天计floorINTNOT NULL所在楼层statusTINYINTDEFAULT 00 空闲 1 入住 2 停用数据字典的写法有个技巧说明列不要复制字段名的英文含义要写业务语义。比如 status 写0 空闲 1 入住 2 停用而不是状态字段。这页做完文档的正文部分基本合格。4.2 使用教程怎么写从 python 安装到 vscode 环境配置一步步可复现README 使用教程的目标是换一台干净的电脑照着做十分钟能跑起来。很多从免费 python 源码下载的现成项目教程只有一句python main.py依赖和数据库初始化全跳过了这种教程等于没有。规范的 README 至少包含环境准备、依赖安装、数据库导入、启动四步# 1. 确认 python 版本要求 3.8 以上 python --version # 2. 创建并激活虚拟环境vscode 里再选这个解释器 python -m venv .venv source .venv/bin/activate # Windows 用 .venv\Scripts\activate.bat # 3. 安装唯一的外部依赖 pip install pymysql # 4. 导入数据库init.sql 在项目根目录 mysql -u root -p init.sql # 5. 启动程序 python main.py每一步都值得写一句解释。虚拟环境这一步最容易忽略但正是它避免了装了一堆全局包互相打架的黑匣子问题。vscode 里做完这步后按 CtrlShiftP 执行 Python: Select Interpreter选中 .venv 对应的解释器python 环境配置才算闭环。数据库导入除了命令行也可以用 Navicat 连接数据库后直接运行 init.sql 文件效果一样两种方式在教程里写一种主路径即可。最后在教程开头加一句运行前先改 config.py 里的密码为本机 MySQL 密码能挡住一半新手提问。4.3 演示脚本两分钟讲清楚老师问不倒答辩演示要提前排演顺序比内容重要。我的演示顺序固定四步先打开 Navicat 展示三张表结构再查一遍空闲房源然后现场做一次入住、退房全流程最后跑一条统计 SQL 收尾。整个流程控制在两分钟内重点不是功能多而是让老师看清你的操作对应数据库里哪条数据变了。入住的演示配合口头讲解现在 orders 表多了一行room 表 201 的状态从 0 变 1。退房同理订单状态变 1房态归位total_amount 是自动算出来的。老师后续问如果两个人同时订同一间房怎么办就答第 3.2 节的 FOR UPDATE 加事务问房价策略变了怎么办就答价格在 room 表扩展成价格策略表不影响现有逻辑。这两个答案准备好项目的高分基本稳了。再说一个实战建议答辩前一定从 init.sql 重新初始化一次数据库保证演示环境是干净状态前面试过退房、改过的脏数据全部清掉。这就是整套方案的后悔药比任何调试技巧都管用。5. 避坑排查连接失败、中文乱码、保留字和外键的高频翻车现场这一章是血泪经验汇总。以下五个坑是我见学生踩得最多的按现象、原因、解决三段写每条都值得提前预防。5.1 Navicat 连不上 MySQL先查服务是否启动再查连接方式现象Navicat 或 pymysql 报 Cant connect to MySQL server 或 10061 错误程序一启动就死在这一步。原因八成是 MySQL 服务没启动。Windows 下安装 MySQL 后服务默认可能是手动状态重启电脑就没起来还有两成是 pymysql 的 host 写了 localhost被解析成 IPv6 的 ::1而 MySQL 只监听了 127.0.0.1。解决先确认服务Windows 在服务管理器里找 MySQL 并启动或执行net start mysql80版本不同服务名可能不同同时把 config.py 和 Navicat 的 host 统一改成 127.0.0.1。排错时顺手执行ping 127.0.0.1和netstat -ano | findstr 3306能确认端口是否在监听。5.2 控制台和数据库里全是问号字符集要全链路统一 utf8mb4现象INSERT 报 Incorrect string value: \xE6...或者数据存进去中文正常读出来全是问号。原因字符集链路断了一环。常见三种情况建库时没指定字符集走了默认 latin1pymysql 连接参数没写 charsetWindows 终端用 GBK 显示数据库里其实是对的看起来像乱码。解决建库语句写DEFAULT CHARACTER SET utf8mb4连接参数写charsetutf8mb4这是两条铁律。终端乱码用chcp 65001切到 UTF-8 后再跑程序或者去 Navicat 里看数据确认是否真的乱码。排查时执行SHOW CREATE TABLE room;查看表级字符集别只在代码层面改。5.3 SQL 语法报错 1064order 是 MySQL 保留字别拿它当表名现象执行CREATE TABLE order (...)或INSERT INTO order ...直接报 1064 语法错误反复检查 SQL 都看不出问题。原因ORDER 是 MySQL 的保留字用于 ORDER BY 排序直接当表名和标识符用会触发语法解析错误。这套路同样适用于 user、group、system 等保留字。解决表名统一用复数 orders 绕开保留字这是最省事的方式如果非要叫 orderSQL 里必须用反引号包起来写成order。我的建议是直接改名因为文档、代码、口头描述里到处都要写表名带反引号反而容易抄错。5.4 删房间被外键拦住先处理未结算订单或者改用状态位软删除现象想清理测试数据时执行DELETE FROM room WHERE room_id1报错 foreign key constraint fails。原因orders 表里还有订单引用这个房间的 room_id外键约束不允许删除被引用的父表记录。这其实说明外键设计生效了是好事但演示时处理不当会冷场。解决先查有没有未结算的入住订单处理完再删SELECT room_no FROM room r WHERE r.room_id IN (SELECT room_id FROM orders WHERE status 0);更常见的工程做法是软删除不物理删除房间而是把 status 改成 2 表示停用查询空闲房时带上 status0 条件自然就过滤掉了。这样既保留历史订单的关联完整性又实现了删除语义答辩时这段回答是加分项。5.5 pymysql 报 Authentication pluginMySQL 8 默认密码插件与旧驱动不兼容现象pymysql 连接时报 Authentication plugin caching_sha2_password cannot be loaded或者提示缺少 cryptography 包。原因MySQL 8.0 把默认密码插件改成 caching_sha2_password较老版本的 PyMySQL 不认识这个插件需要额外的 cryptography 库支持加密通信。解决两条路任选。优先执行pip install cryptography装完一般就通了改动最小如果不想装也可以把账号认证方式改回 mysql_native_passwordALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 123456; FLUSH PRIVILEGES;提醒一点如果用了改插件这条路换到别的电脑演示前要记得目标机器的 MySQL 也做同样处理否则同样的代码换个环境又崩。所以我的默认选择永远是补装 cryptography。6. 再往前走一步tkinter 界面、月度报表和连接池够答辩加分6.1 三天套一个 tkinter 界面不引第三方库就能交差命令行版跑通之后很多老师会问一句有界面吗。答案其实不难Python 自带的 tkinter 就够了不装任何第三方库三天能套完。把 service.py 的函数原封不动接进按钮事件就行import tkinter as tk from tkinter import messagebox from service import check_in app tk.Tk() app.title(酒店管理系统) def submit(): try: check_in(no.get(), name.get(), idcard.get(), phone.get(), float(deposit.get())) messagebox.showinfo(提示, 入住成功) except Exception as e: messagebox.showerror(错误, str(e)) tk.Label(app, text房间号).pack() no tk.Entry(app); no.pack() # 姓名、身份证、电话、押金四个输入框同理省略重复代码 tk.Button(app, text入住登记, commandsubmit).pack() app.mainloop()界面代码的价值不是好看而是证明你的业务函数和界面是解耦的。老师问换界面会影响业务吗你答不影响service.py 一套逻辑两头用这句话比界面本身更能拿分。6.2 报表查询和连接池把数据库含量再抬一档总停留在增删改查会被认为数据库含量不足加一张月度报表能明显拉高印象分。统计退房订单的月度营收一条 SQL 就够SELECT DATE_FORMAT(checkout_time, %Y-%m) AS 月份, COUNT(*) AS 订单数, SUM(total_amount) AS 营收 FROM orders WHERE status 1 GROUP BY DATE_FORMAT(checkout_time, %Y-%m) ORDER BY 月份;这条 SQL 展示了聚合、分组、日期函数三个知识点答辩时提一句用 GROUP BY 按月份聚合SUM 算营收数据库功底立刻和其他同学拉开差距。再往上就是连接池课设规模其实用不上但如果老师问了高并发怎么办能答出方案就说明你见过工程实践from dbutils.pooled_db import PooledDB import pymysql pool PooledDB(creatorpymysql, maxconnections10, mincached2, host127.0.0.1, port3306, userroot, password123456, databasehotel_db, charsetutf8mb4) def get_conn(): return pool.connection()注意安装包名是 DBUtils导入路径是 dbutils.pooled_db这两个名字不一致我第一次用的时候也踩过。连接池的思路是复用连接而不是每次新建maxconnections 控制上限mincached 保持常驻连接数正好把第 3 章每次新建连接的做法做了一个工程化升级。说到智慧酒店管理系统这类更完整的方向无非是在这三张表上继续长会员表、价格策略表、房态日志表、保洁工单表。但课设的核心始终是先把三张表的关系和事务讲透。我自己的习惯是答辩前永远做两件事从 init.sql 重新初始化数据库然后按演示脚本完整走一遍入住退房。当初我用 FLOAT 存金额被老师当场指出精度问题从那以后金额一律 DECIMAL这个教训比任何文档都深刻。希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。