简介这份资源是面向高校计算机相关专业学生的数据库课程设计完整项目包以宾馆管理系统为选题采用Python与PyQt构建图形界面配合SQL数据库完成数据存储与业务逻辑适合正在准备课程设计、需要可运行参考案例的初学者与中级学习者。压缩包共490个文件约14.06MB其中316个py源码文件构成核心业务与界面逻辑9个ui界面文件与31个png、7个jpg图片资源共同支撑可视化交互另含pyd、dll、exe等运行依赖及sql建库脚本、txt说明文档目录结构完整便于按模块阅读与二次修改。目前已有948人学习下载说明该案例在同类课程设计中具有较高参考价值。读者可从中获取完整的系统实现思路、数据库表结构设计、PyQt界面搭建方式以及依赖环境配置参考适合作为课程设计模板或功能扩展的起点。1. 宾馆管理系统课设拆包从建表到 PyQt 界面这套源码能省你多少时间如果你正在做数据库课程设计选题又恰好是宾馆管理大概率会遇到一个尴尬局面需求文档写得像模像样ER 图也画了但真到写代码那一步发现光是把 MySQL 表建好、把 Python 连上数据库、再拖出一个能看的 PyQt 界面就能耗掉整整一周。更别提还有入住退房逻辑、房态联动、账单计算这些绕不开的坑。这份「数据库课程设计-宾馆管理系统.zip」就是冲着这个场景来的——它把数据库脚本、Python 后端逻辑和 PyQt 前端界面打包在一起适合两类人一是时间紧、需要一份能跑通的参考实现来对照改写的同学二是想看看一个完整 CRUD 项目到底该怎么分层、怎么组织代码的初学者。关键词里提到的数据库、Python、PyQt 三个技术点在这份资源里都有对应的落地文件不是那种只有文档没有代码的空壳包。2. 先看数据库层建表脚本与 MySQL 连接池的取舍2.1 表结构设计房间、客人、订单三张核心表怎么拆拿到任何一份宾馆管理系统的源码第一件事不是急着跑界面而是先看它的建表脚本。因为表结构决定了后面所有业务逻辑的天花板。这份资源里通常会有hotel.sql或类似的初始化脚本核心表一般围绕三块展开房间信息表、客人信息表、入住订单表。房间表的关键字段包括房间号、房型、价格、状态空闲/已入住/维修。客人表存身份证号、姓名、联系方式。订单表则是关联表把客人和房间通过入住时间、退房时间、押金、实际消费串起来。这里有一个常见的设计分歧房态到底存在房间表里还是通过订单表实时计算我一般会建议初学者把房态冗余到房间表因为 PyQt 界面刷新时直接查房间表比联表计算快得多代码也好写。代价是退房时要记得同步更新房间状态这个坑后面会细说。-- 房间表房态冗余存储方便界面直接读取 CREATE TABLE room ( room_id INT PRIMARY KEY AUTO_INCREMENT, room_number VARCHAR(10) NOT NULL UNIQUE, room_type VARCHAR(20) NOT NULL, price DECIMAL(10,2) NOT NULL, status TINYINT DEFAULT 0 COMMENT 0空闲 1已入住 2维修 ); -- 订单表记录入住退房时间与押金 CREATE TABLE order_info ( order_id INT PRIMARY KEY AUTO_INCREMENT, guest_id INT NOT NULL, room_id INT NOT NULL, check_in DATETIME NOT NULL, check_out DATETIME, deposit DECIMAL(10,2), total_cost DECIMAL(10,2), FOREIGN KEY (guest_id) REFERENCES guest(guest_id), FOREIGN KEY (room_id) REFERENCES room(room_id) );上面这段 SQL 里status字段用 TINYINT 而不是字符串是为了在 Python 里做条件判断时更省事。order_info表名没有用order因为order是 MySQL 关键字直接拿来当表名会报语法错误这是很多人建表时踩的第一个坑。外键约束建议加上虽然课设答辩时老师不一定查但有了外键删除房间时会自动阻止误删有订单的房间省得你手动写校验逻辑。2.2 Python 连接 MySQL用 PyMySQL 还是 mysql-connector数据库建好之后下一步是让 Python 能连上。这份资源里大概率用的是 PyMySQL 或者 mysql-connector-python。两者都能用但 PyMySQL 更轻量安装时不需要额外编译依赖适合在机房电脑或者自己笔记本上快速跑起来。连接池的问题在课设里经常被过度设计——有些教程一上来就教你上连接池结果代码复杂度飙升调试难度翻倍。我的建议是课设阶段直接用单连接加try...except重连就够了除非你的界面有大量并发查询否则连接池带来的收益微乎其微。import pymysql def get_connection(): return pymysql.connect( hostlocalhost, userroot, passwordyour_password, databasehotel_db, charsetutf8mb4, cursorclasspymysql.cursors.DictCursor ) # 查询空闲房间示例 def get_free_rooms(): conn get_connection() try: with conn.cursor() as cur: cur.execute(SELECT * FROM room WHERE status 0) return cur.fetchall() finally: conn.close()这段代码里cursorclasspymysql.cursors.DictCursor是关键它让查询结果以字典形式返回而不是默认的元组。这样在 PyQt 里填充表格时可以直接用字段名取值不用记索引位置代码可读性高很多。charsetutf8mb4是为了支持中文姓名和备注用utf8在某些 MySQL 版本下会出乱码。每次查询后关闭连接是必须的否则多次刷新界面后连接数会爆掉报Too many connections错误。2.3 增删改查的封装别把 SQL 散落在界面代码里很多课设源码的通病是把 SQL 语句直接写在 PyQt 的按钮点击事件里导致界面文件和数据库操作耦合在一起。这份资源如果结构清晰应该会有一个单独的dao.py或db_helper.py来封装所有数据库操作。这样做的好处是当老师要求你换数据库或者加字段时你只需要改一个文件而不是在几百行界面代码里到处找 SQL。# dao.py 中封装入住登记操作 def check_in(guest_id, room_id, deposit): conn get_connection() try: with conn.cursor() as cur: # 插入订单 cur.execute( INSERT INTO order_info (guest_id, room_id, check_in, deposit) VALUES (%s, %s, NOW(), %s), (guest_id, room_id, deposit) ) # 同步更新房态 cur.execute(UPDATE room SET status 1 WHERE room_id %s, (room_id,)) conn.commit() except Exception as e: conn.rollback() raise e finally: conn.close()注意这里用了conn.commit()和conn.rollback()配对。入住登记涉及两张表的写操作如果插入订单成功但更新房态失败没有事务回滚的话房间就会显示空闲但实际已有订单造成超卖。这是宾馆管理系统里最典型的并发问题课设答辩时如果能主动提到这一点加分不少。3. PyQt 界面层用 Qt Designer 拖出主界面后怎么接后端3.1 界面文件与逻辑文件的分离ui 转 py 的正确姿势PyQt 开发最常见的翻车现场是用 Qt Designer 拖完界面保存成.ui文件然后直接手写代码去加载它结果每次改界面都要重新生成一遍 Python 文件改一次界面丢一次逻辑代码。正确的做法是把.ui文件用pyuic5转成ui_main.py然后单独写一个main.py继承这个界面类所有业务逻辑写在main.py里。这样界面调整时只需要重新生成ui_main.py业务代码不受影响。# 将 designer 保存的 mainwindow.ui 转为 Python 文件 pyuic5 -o ui_main.py mainwindow.ui转换命令本身很简单但要注意pyuic5的版本要和 PyQt5 匹配。如果你用的是 PyQt6命令要换成pyuic6生成的代码导入语句也会从PyQt5变成PyQt6。很多人在这一步报ModuleNotFoundError就是因为装的是 PyQt5 却用了 pyuic6或者反过来。3.2 表格刷新与信号槽房态变化后界面怎么自动更新宾馆管理系统的核心界面通常是一个房间列表的表格显示房间号、房型、价格、状态。当用户点击「入住」或「退房」按钮后表格需要立即刷新。PyQt 里实现这个的标准做法是信号槽机制按钮的clicked信号连接到自定义的槽函数槽函数里调用数据库操作然后重新查询并填充表格。from PyQt5.QtWidgets import QMainWindow, QTableWidgetItem from ui_main import Ui_MainWindow from dao import get_all_rooms, check_in class HotelWindow(QMainWindow, Ui_MainWindow): def __init__(self): super().__init__() self.setupUi(self) self.btn_check_in.clicked.connect(self.handle_check_in) self.load_rooms() def load_rooms(self): rooms get_all_rooms() self.table_rooms.setRowCount(len(rooms)) for row, room in enumerate(rooms): self.table_rooms.setItem(row, 0, QTableWidgetItem(room[room_number])) self.table_rooms.setItem(row, 1, QTableWidgetItem(room[room_type])) self.table_rooms.setItem(row, 2, QTableWidgetItem(str(room[price]))) status_map {0: 空闲, 1: 已入住, 2: 维修} self.table_rooms.setItem(row, 3, QTableWidgetItem(status_map[room[status]])) def handle_check_in(self): # 获取当前选中行执行入住逻辑后刷新表格 current_row self.table_rooms.currentRow() if current_row 0: room_number self.table_rooms.item(current_row, 0).text() # 调用 dao 层完成入住然后重新加载 self.load_rooms()这段代码里status_map字典把数据库里的数字状态映射成中文显示是界面层该做的事不要把这个转换逻辑塞到 SQL 里用CASE WHEN写那样后期改显示文案还得动数据库。load_rooms每次全量刷新对于课设级别的数据量几十到几百个房间完全够用不需要做增量更新过度优化反而容易引入 bug。3.3 入住退房联动一个按钮背后要动几张表入住和退房是宾馆管理系统里业务逻辑最密集的两个操作。入住时要做的事包括检查房间是否空闲、插入订单记录、更新房间状态为已入住。退房时要做的事包括计算实际消费入住天数乘以房价扣除押金、更新订单的退房时间和总消费、把房间状态改回空闲。任何一个环节漏掉都会导致数据不一致。def check_out(order_id, room_id): conn get_connection() try: with conn.cursor() as cur: # 查询入住时间和押金 cur.execute(SELECT check_in, deposit FROM order_info WHERE order_id %s, (order_id,)) order cur.fetchone() # 计算消费金额天数 * 房价这里简化处理 cur.execute( UPDATE order_info SET check_out NOW(), total_cost DATEDIFF(NOW(), check_in) * (SELECT price FROM room WHERE room_id %s) WHERE order_id %s , (room_id, order_id)) cur.execute(UPDATE room SET status 0 WHERE room_id %s, (room_id,)) conn.commit() except Exception as e: conn.rollback() raise e finally: conn.close()退房逻辑里用DATEDIFF计算天数是最简做法但要注意它算的是日期差如果客人当天入住当天退房结果是 0 天实际应该按 1 天收费。更严谨的做法是用TIMESTAMPDIFF(HOUR, check_in, NOW())然后向上取整。这个细节在课设答辩时如果被问到能答上来就是加分项。4. 避坑与排查课设跑不起来时先查这五个地方4.1 现象PyQt 界面能显示但表格空白控制台无报错原因通常是数据库查询返回了空结果但代码没有对空结果做处理或者数据库连接时用了错误的库名。还有一种可能是DictCursor没生效返回的是元组而界面代码用字典键取值导致TypeError被外层try吞掉了。解决方法是先在dao.py里单独跑一次查询打印结果确认数据能取到再排查界面层。4.2 现象中文显示成问号或乱码原因有两个层面数据库表的字符集不是utf8mb4或者 Python 连接时没指定charset。建表时如果用了默认的latin1后面再怎么改连接参数都救不回来只能重建表。解决方法是建库建表时统一用CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci连接参数里也加上charsetutf8mb4。4.3 现象入住后房间状态没变但订单表里已经有记录这是典型的事务未提交或房态更新遗漏。检查check_in函数里有没有conn.commit()以及有没有执行UPDATE room SET status 1。如果用了连接池或者自动提交模式commit可能不生效需要确认连接的autocommit属性。我一般会在get_connection里显式设置autocommitFalse所有写操作手动提交避免玄学问题。4.4 现象重复入住同一房间系统不报错原因是入住前没有校验房间当前状态。正确的做法是在check_in函数开头先查一次SELECT status FROM room WHERE room_id %s如果status ! 0就抛出异常或返回错误提示。这个校验放在数据库层用唯一索引做也行但课设里用代码校验更直观老师也更容易看懂。4.5 现象PyQt 界面卡死点击按钮没反应通常是数据库操作耗时太长阻塞了 UI 线程。课设数据量小一般不会卡但如果连接超时或者 SQL 写错了导致全表扫描就会卡住。解决方法是在dao.py里给每个查询加上超时参数或者把耗时操作放到QThread里。课设阶段更简单的做法是确保 SQL 走了索引比如room_number和status字段加索引。5. 进阶技巧用视图和触发器把业务逻辑下沉到数据库课设做到后面如果想让答辩老师眼前一亮可以试试把部分业务逻辑从 Python 挪到数据库层。比如创建一个视图直接展示「当前入住客人及房间信息」这样界面层只需要查视图不用写联表 SQL。再比如给order_info表加一个触发器当插入新订单时自动把对应房间状态改为已入住这样即使 Python 代码忘了更新房态数据库也能兜底。-- 创建视图当前入住详情 CREATE VIEW v_current_guests AS SELECT g.name, g.phone, r.room_number, r.room_type, o.check_in, o.deposit FROM order_info o JOIN guest g ON o.guest_id g.guest_id JOIN room r ON o.room_id r.room_id WHERE o.check_out IS NULL; -- 创建触发器插入订单后自动更新房态 DELIMITER // CREATE TRIGGER trg_check_in AFTER INSERT ON order_info FOR EACH ROW BEGIN UPDATE room SET status 1 WHERE room_id NEW.room_id; END // DELIMITER ;视图的好处是界面层代码更干净SELECT * FROM v_current_guests一行就能拿到所有需要展示的字段。触发器则是一把双刃剑它确实能防止遗漏更新但调试时如果忘了触发器的存在可能会被「为什么房态自己变了」搞懵。我一般只在课设答辩前临时加上触发器演示平时开发还是用 Python 显式控制这样逻辑更透明。验证触发器是否生效的方法很简单手动往order_info插一条测试数据然后查room表的status字段看是否自动变成了 1。如果没变检查触发器的DELIMITER是否正确设置以及NEW.room_id是否对应了正确的列名。另一个容易翻车的地方是触发器里用了UPDATE但忘了加WHERE条件导致所有房间状态都被改掉——这种血泪经验我建议你直接在测试库上试别在主库上操作。从那以后我每次拿到任何课设源码都强制先跑一遍建表脚本再单独测一遍数据库连接最后才开界面。这个顺序能帮你把问题隔离在最小范围内不至于界面报错时连是数据库没连上还是代码写错了都分不清。希望帮到你。本文还有配套的精品资源点击获取
企业数字化 ERP 产品动态
相关推荐
拼团交易平台系统云部署第二阶段:Nginx 负载多实例部署支付商城与拼团服务 文档教程后端 【免费下载链接】CodeGuide :books: 本代码库是作者小傅哥多年从事一线互联网 Java 开发的学习历程技术汇总,旨在为大家提供一个清晰详细的学习教程,侧重点更倾向编写Java核心内容。如果本仓库能为您提供帮助,请给予支持(关注、… · 2026/9/25 1:38:50
Altium Designer元件库命名规则与74LS/CD4000系列中英文对照指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:38:50
Apache Pulsar 二进制协议规范详解:从帧结构到 Lookup 的服务端通信原理 消息队列后端流处理 【免费下载链接】pulsar Apache Pulsar - distributed pub-sub messaging system 项目地址: https://gitcode.com/gh_mirrors/pulsar28/pulsar 点击查看 免费下载 Apache Pulsar 的客户端与 Broker 之间并不依赖 HTTP 或 gRPC 等通用 RPC 框架&… · 2026/9/25 2:46:01
把智能塞进 if 语句:Jev 规则引擎如何用条件分支替代部分大模型决策 1. 当"智能"被压缩进一行 if 语句:Jev 到底在赌什么第一次看到"把智能塞进 if 语句"这个说法,我的反应是:又一个标题党。毕竟这几年"颠覆 Transformer""抛弃注意力机制"的口号喊了太多,真… · 2026/9/25 2:45:55
RocketRide 的 llm_gemini 节点:在 AI Pipeline 中接入 Google Gemini 模型 【免费下载链接】rocketride-server High-performance AI pipeline engine with a C core and 50 Python-extensible nodes. Build, debug, and scale LLM workflows with 13 model providers, 8 vector databases, and agent orchestration, all from your IDE. Includes VS C… · 2026/9/25 2:45:49
GoLearn 安装与环境配置指南:从 Go 工具链到 OpenBLAS 的完整搭建路径 机器学习人工智能 【免费下载链接】golearn Machine Learning for Go 项目地址: https://gitcode.com/gh_mirrors/go/golearn 点击查看 免费下载 GoLearn 是 Go 语言的一个"开箱即用"的机器学习函数库。本篇基于仓库内的 安装文档,完整覆盖其… · 2026/9/25 2:45:49
jc 解析 efibootmgr:将 Linux UEFI 启动项管理输出转换为 JSON 开发工具 【免费下载链接】jc CLI tool and python library that converts the output of popular command-line tools, file-types, and common strings to JSON, YAML, or Dictionaries. This allows piping of output to tools like jq and simplifying automation scripts.… · 2026/9/25 2:45:49
VSCode + Markdown All in One:高效博客写作的完整指南 1. 这篇博客,VSCode Markdown All in One 能解决什么问题经常有朋友问我:"你平时写博客用什么工具?" 我说 VSCode 加一个 Markdown All in One 插件。对方接着就问:"这玩意儿到底好在哪?我用 Word 写得… · 2026/9/25 2:45:43
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37