数据库课程设计机房管理系统:SQL Server与PowerBuilder实战

发布时间:2026/10/11 16:24:39
数据库课程设计机房管理系统:SQL Server与PowerBuilder实战
简介这份资源是广东工业大学数据库课程设计的完整Word版报告面向高校数据库相关专业学生及需要完成课程设计的学习者聚焦机房管理系统的设计与实现。报告以SQL Server 2005为数据库平台、PowerBuilder为开发工具系统梳理了从需求分析到应用程序调试的全过程可帮助读者理解一个完整数据库应用项目的开发脉络。资源包内含1个doc文档大小约1.27MB内容涵盖系统需求分析与功能设计、总体功能模块图与菜单设计、E-R图与数据库逻辑模型、T-SQL建表语句以及模块查询调试与成果展示等章节并附有总结与致谢。其中设备采购、登记、借用归还、维修报废及机房上机安排等业务场景描述具体适合作为课程设计选题参考、报告撰写模板或数据库建模练习的对照材料。目前已有185人学习下载对需要快速把握机房管理系统设计思路与文档结构的读者具有一定参考价值。1. 从一份课程设计文档说起机房管理系统到底要解决什么很多同学拿到「数据库课程设计机房管理系统设计」这个题目时第一反应是去搜一份完整文档把表建出来、界面拖出来就交差。但真正做过机房管理的人会告诉你这个题目的核心难点从来不是画几个窗体而是把「机器状态」「上机计费」「学生账户」这三件事在数据库里对齐。机房管理系统要解决的是一台机器什么时候被谁占用、用了多久、扣了多少钱、坏了怎么记录。它适合数据库入门者练手也适合想搞懂 T-SQL 事务和并发控制的开发者。热搜里常出现 SQL Server、PowerBuilder、T-SQL 这些词说明这套技术栈在国内课程设计里依然是主流组合。下面我按实际落地的顺序把从建库到并发扣费的完整路径拆开讲。2. 选型与建库SQL Server PowerBuilder 这套组合为什么还在用2.1 为什么课程设计普遍选 SQL Server 而不是 MySQL机房管理系统的数据特征很明确强事务、多表关联、需要存储过程和触发器。SQL Server 在 T-SQL 层面提供的BEGIN TRAN/COMMIT/ROLLBACK语义清晰配合WITH (UPDLOCK)做行级锁非常直接。MySQL 当然也能做但课程设计场景下SQL Server 的图形化管理工具和 PowerBuilder 的 DataWindow 配合更顺——DataWindow 可以直接绑定存储过程省掉大量手写 CRUD。另一个现实原因是教学环境。很多学校机房预装的就是 SQL Server 2012 或 2019PowerBuilder 12.5 也是常见版本。你不需要追新用sql server 2012下载或sql server 2019安装教程里能找到的版本即可。安装时注意选「混合认证模式」否则 PowerBuilder 连不上。提示安装 SQL Server 时如果遇到「密码到期」提示在 SSMS 里执行ALTER LOGIN sa WITH PASSWORD新密码即可不要重装。2.2 机房管理系统的最小表结构设计不要一上来就建十几张表。核心只有五张学生表、机器表、上机记录表、充值记录表、管理员表。下面是我一般会用的建表脚本字段类型和约束都经过实际验证。-- 学生表账户余额用 decimal避免 float 精度问题 CREATE TABLE Student ( StuID VARCHAR(12) PRIMARY KEY, -- 学号 StuName NVARCHAR(20) NOT NULL, Balance DECIMAL(10,2) DEFAULT 0 CHECK (Balance 0), Status TINYINT DEFAULT 1 -- 1正常 0冻结 ); -- 机器表机房编号机器号做联合唯一 CREATE TABLE Machine ( MachID INT IDENTITY(1,1) PRIMARY KEY, RoomNo VARCHAR(10) NOT NULL, MachNo VARCHAR(10) NOT NULL, MachStatus TINYINT DEFAULT 0, -- 0空闲 1使用中 2故障 CONSTRAINT UQ_Mach UNIQUE (RoomNo, MachNo) ); -- 上机记录表这是计费的核心表 CREATE TABLE UseLog ( LogID BIGINT IDENTITY(1,1) PRIMARY KEY, StuID VARCHAR(12) NOT NULL, MachID INT NOT NULL, BeginTime DATETIME NOT NULL, EndTime DATETIME NULL, Fee DECIMAL(10,2) NULL, FOREIGN KEY (StuID) REFERENCES Student(StuID), FOREIGN KEY (MachID) REFERENCES Machine(MachID) );逻辑说明Balance用DECIMAL(10,2)而不是FLOAT因为金额计算不能有浮点误差。UseLog的EndTime允许为空表示正在上机。Machine表的MachStatus是状态机的核心字段上机和下机都要更新它。参数说明StuID用VARCHAR(12)兼容不同学校学号长度Fee允许为空是因为下机时才计算联合唯一约束UQ_Mach防止同一机房出现重复机器号。2.3 PowerBuilder 连接 SQL Server 的配置步骤PowerBuilder 连 SQL Server 走 ODBC 或专用接口。课程设计里最稳的是 ODBC。步骤在 Windows 的 ODBC 数据源管理器里新建「系统 DSN」驱动选SQL Server。名称填jfgl服务器填localhost或.\SQLEXPRESS。登录方式选「使用用户输入登录 ID 和密码」测试连接用sa和你的密码。在 PowerBuilder 的 Database Profile 里选 ODBC选刚建的jfgl点 Connect。连上后DataWindow 的 SQL 语句里可以直接写SELECT * FROM UseLog WHERE EndTime IS NULL来查当前在线记录。注意 PowerBuilder 12.5 对NVARCHAR支持没问题但如果你用的是更老的版本中文可能乱码建库时排序规则选Chinese_PRC_CI_AS。3. 上机与计费T-SQL 存储过程怎么写才不出错3.1 上机操作一条 UPDATE 加一条 INSERT 的原子性上机的业务逻辑是检查学生余额是否足够、检查机器是否空闲、把机器状态改为使用中、插入一条上机记录。这四步必须在一个事务里。CREATE PROCEDURE sp_BeginUse StuID VARCHAR(12), MachID INT AS BEGIN SET NOCOUNT ON; BEGIN TRY BEGIN TRAN; -- 检查学生状态和余额加更新锁防止并发扣费 IF NOT EXISTS (SELECT 1 FROM Student WITH (UPDLOCK) WHERE StuID StuID AND Status 1 AND Balance 0) BEGIN ROLLBACK; RAISERROR(学生不存在、已冻结或余额不足, 16, 1); RETURN; END -- 检查机器是否空闲同样加锁 IF NOT EXISTS (SELECT 1 FROM Machine WITH (UPDLOCK) WHERE MachID MachID AND MachStatus 0) BEGIN ROLLBACK; RAISERROR(机器不存在或正在使用, 16, 1); RETURN; END UPDATE Machine SET MachStatus 1 WHERE MachID MachID; INSERT INTO UseLog (StuID, MachID, BeginTime) VALUES (StuID, MachID, GETDATE()); COMMIT; END TRY BEGIN CATCH IF TRANCOUNT 0 ROLLBACK; THROW; END CATCH END逻辑说明WITH (UPDLOCK)是关键。它在上锁的同时阻止其他事务读取避免两个学生同时抢同一台机器。TRY...CATCH保证任何一步失败都回滚。RAISERROR把错误信息抛给 PowerBuilder 端显示。参数说明StuID和MachID由 DataWindow 传入。Balance 0是最低门槛实际可以改成Balance 1表示至少够一小时。3.2 下机计费按分钟还是按小时费率怎么存计费规则通常有两种按小时整点计费或按分钟计费。课程设计里建议用按分钟因为逻辑简单且不容易扯皮。费率不要写死在代码里单独建一张Rate表。CREATE TABLE Rate ( RateID INT PRIMARY KEY, RateName VARCHAR(20), PricePerMin DECIMAL(10,4) NOT NULL ); INSERT INTO Rate VALUES (1, 普通费率, 0.05);下机存储过程CREATE PROCEDURE sp_EndUse LogID BIGINT AS BEGIN SET NOCOUNT ON; DECLARE StuID VARCHAR(12), MachID INT, BeginTime DATETIME; DECLARE Minutes INT, Fee DECIMAL(10,2), Price DECIMAL(10,4); BEGIN TRY BEGIN TRAN; SELECT StuID StuID, MachID MachID, BeginTime BeginTime FROM UseLog WITH (UPDLOCK) WHERE LogID LogID AND EndTime IS NULL; IF StuID IS NULL BEGIN ROLLBACK; RAISERROR(记录不存在或已下机, 16, 1); RETURN; END SELECT Price PricePerMin FROM Rate WHERE RateID 1; SET Minutes DATEDIFF(MINUTE, BeginTime, GETDATE()); IF Minutes 1 SET Minutes 1; -- 不足一分钟按一分钟算 SET Fee Minutes * Price; UPDATE UseLog SET EndTime GETDATE(), Fee Fee WHERE LogID LogID; UPDATE Machine SET MachStatus 0 WHERE MachID MachID; UPDATE Student SET Balance Balance - Fee WHERE StuID StuID; COMMIT; END TRY BEGIN CATCH IF TRANCOUNT 0 ROLLBACK; THROW; END CATCH END逻辑说明DATEDIFF(MINUTE, ...)算出上机分钟数不足一分钟按一分钟算这是机房管理的常见做法。扣费、改机器状态、写结束时间三步在同一个事务里任何一步失败都不会出现「机器空了但钱没扣」的情况。参数说明LogID是上机记录的主键由界面选中行传入。PricePerMin用DECIMAL(10,4)是为了支持分以下的费率精度。3.3 在 PowerBuilder 里调用存储过程并刷新 DataWindowPowerBuilder 调用存储过程有两种方式DataWindow 的Stored Procedure数据源或Dynamic SQL。推荐用 DataWindow因为能自动映射结果集。// 上机按钮的 Clicked 事件 long ll_ret string ls_stuid, ls_machid ls_stuid sle_stuid.Text ls_machid sle_machid.Text // 用 Dynamic SQL 调用存储过程 EXECUTE sp_BeginUse :ls_stuid, :ls_machid; IF SQLCA.SQLCode 0 THEN MessageBox(上机失败, SQLCA.SQLErrText) ELSE MessageBox(成功, 上机已开始) dw_online.Retrieve() // 刷新在线列表 END IF逻辑说明EXECUTE是 PowerBuilder 调用存储过程的语法冒号表示变量绑定。SQLCA.SQLCode非零表示出错SQLErrText里就是存储过程RAISERROR抛出的中文信息。参数说明sle_stuid和sle_machid是界面上的单行编辑框。dw_online是绑定SELECT * FROM UseLog WHERE EndTime IS NULL的 DataWindowRetrieve()重新查一次。4. 避坑与排查机房管理系统开发中最容易翻车的五个点4.1 并发上机导致同一台机器被两个人占用现象两个学生同时点「上机」选同一台机器结果两条上机记录都插入了机器状态也是使用中。原因检查机器空闲和更新机器状态之间没有加锁两个事务都读到了MachStatus 0。解决在SELECT机器状态时加WITH (UPDLOCK)如 3.1 节所示。更彻底的做法是把机器状态检查改成UPDATE Machine SET MachStatus 1 WHERE MachID MachID AND MachStatus 0然后检查ROWCOUNT是否为 1。4.2 余额扣成负数现象学生余额 0.5 元上机 2 小时后下机余额变成 -5.5 元。原因上机时只检查了Balance 0没有预扣或冻结额度。解决两种方案。一是上机时预扣一小时费用下机时多退少补二是下机扣费时用UPDATE Student SET Balance Balance - Fee WHERE StuID StuID AND Balance Fee如果ROWCOUNT 0则说明余额不足需要走欠费处理流程。课程设计里推荐第二种逻辑简单。4.3 PowerBuilder 中文乱码现象DataWindow 里查出来的学生姓名显示成问号或方块。原因数据库排序规则不是Chinese_PRC_CI_AS或者 ODBC 驱动没勾选「使用 ANSI 引号」。解决建库时指定COLLATE Chinese_PRC_CI_AS。如果库已经建好执行ALTER DATABASE jfgl COLLATE Chinese_PRC_CI_AS。ODBC 配置里勾选「使用 ANSI 引号」和「执行字符集转换」。4.4 存储过程改了但 PowerBuilder 还在用旧结果现象修改了存储过程的返回字段但 DataWindow 刷新后还是旧数据。原因DataWindow 在第一次Retrieve()时缓存了结果集结构。解决在 PowerBuilder 里重新打开 DataWindow 的 SQL 画板点「重新生成」或手动改Stored Procedure定义。更简单的办法是删掉 DataWindow 重新建一个。4.5 数据库死锁现象高峰期多个学生同时上下机SSMS 里报「事务被选为死锁牺牲品」。原因两个事务互相等待对方持有的锁。比如事务 A 锁了 Student 表等 Machine 表事务 B 锁了 Machine 表等 Student 表。解决统一加锁顺序。所有存储过程都先锁 Student 再锁 Machine或者先锁 Machine 再锁 Student不要混着来。另外尽量缩短事务时间把GETDATE()之类的计算放在事务外。5. 进阶技巧用触发器做余额变动审计和机器状态自动恢复课程设计做到上面基本能跑通了但如果你想拿高分或者真正上线用有两个进阶点值得做。第一个是余额审计。学生余额被扣了事后扯皮说没扣对怎么办建一张BalanceLog表用触发器记录每次余额变动。CREATE TABLE BalanceLog ( LogID BIGINT IDENTITY(1,1) PRIMARY KEY, StuID VARCHAR(12), OldBalance DECIMAL(10,2), NewBalance DECIMAL(10,2), ChangeTime DATETIME DEFAULT GETDATE(), Reason VARCHAR(50) ); CREATE TRIGGER trg_Student_Balance ON Student AFTER UPDATE AS BEGIN IF UPDATE(Balance) BEGIN INSERT INTO BalanceLog (StuID, OldBalance, NewBalance, Reason) SELECT d.StuID, d.Balance, i.Balance, 系统扣费 FROM deleted d INNER JOIN inserted i ON d.StuID i.StuID WHERE d.Balance i.Balance; END END逻辑说明deleted和inserted是 SQL Server 触发器里的两个虚拟表分别代表更新前和更新后的数据。只记录余额真正发生变化的行。Reason字段可以扩展成「充值」「扣费」「退款」等。参数说明AFTER UPDATE表示更新完成后触发。IF UPDATE(Balance)确保只有余额列被修改时才记录避免其他字段更新也触发。第二个是机器状态自动恢复。如果学生下机时程序崩溃机器状态会一直卡在「使用中」。可以写一个定时任务每天凌晨把超过 24 小时未下机的记录强制下机并把机器状态改回空闲。-- 每天凌晨 2 点执行的作业步骤 UPDATE UseLog SET EndTime DATEADD(HOUR, 24, BeginTime), Fee 24 * 60 * (SELECT PricePerMin FROM Rate WHERE RateID 1) WHERE EndTime IS NULL AND DATEDIFF(HOUR, BeginTime, GETDATE()) 24; UPDATE Machine SET MachStatus 0 WHERE MachID IN ( SELECT MachID FROM UseLog WHERE EndTime IS NOT NULL AND DATEDIFF(HOUR, EndTime, GETDATE()) 1 );逻辑说明第一条把超时未下机的记录按 24 小时封顶计费并写入结束时间。第二条把刚被强制下机的机器状态改回空闲。实际部署时用 SQL Server Agent 建作业每天执行一次。参数说明DATEADD(HOUR, 24, BeginTime)把结束时间设为开始后 24 小时。DATEDIFF(HOUR, EndTime, GETDATE()) 1确保只更新刚处理的机器避免影响其他记录。我自己的习惯是任何涉及金额的字段在数据库层面一定要有 CHECK 约束兜底比如Balance 0。程序逻辑再严密也架不住有人直接开 SSMS 改数据。触发器加约束相当于给系统上了双保险。另外课程设计文档里最好把存储过程的测试用例也写进去比如「余额 0.5 元上机 2 小时」这种边界情况答辩时老师一看就知道你真跑过。希望帮到你。本文还有配套的精品资源点击获取