简介这份文档资料是北京信息科技大学信息管理学院《数据库系统及应用实践》的课程设计报告以校园二手交易系统为选题面向数据库课程学习者与需要完成课程设计的在校学生。报告完整呈现了从需求分析、概念模型、逻辑模型到物理模型的设计流程并涉及PowerDesigner建模、SQL Server 2005/2008环境下的视图、触发器、存储过程、安全设计与事务控制等内容还包含个人工作报告与小组分工总结可作为同类课程设计的参考模板。资源包共1个doc文件约1.72MB内容为完整的实验报告正文与附件样例结构清晰便于按章节查阅。目前已有1572人学习下载适合希望理解数据库设计全流程、借鉴报告组织方式或准备课程设计答辩的读者参考使用。1. 数据库课程设计(5).doc从一份文档到能跑的系统中间隔着什么很多人拿到“数据库课程设计(5).doc”这个标题第一反应是去找一份现成的文档模板把表结构、E-R图、功能截图往里一贴就交差。但真正做过课程设计的人知道这份文档背后对应的是一套能跑起来的数据库应用系统——SQL Server 建库建表、PowerDesigner 画模型、Visual Studio 写前端最后把设计思路和实现过程整理成文档。文档只是结果过程才是核心。这个标题适合两类人一类是正在做数据库课程设计的学生需要一套从建模到编码再到文档的完整路径另一类是想用一个小型项目练手 SQL Server 和 C# 的开发者需要一个结构清晰、规模可控的练手项目。它解决的不是“怎么写文档”的问题而是“怎么从零搭出一个有增删改查、有事务、有约束的数据库应用并且把每一步的设计决策讲清楚”的问题。接下来按实际动手顺序拆开讲。2. 先定业务场景再建表数据库课程设计的选题与建模路径2.1 选题决定了后面 80% 的工作量数据库课程设计最常见的翻车方式不是 SQL 写错了而是一开始选题太大。比如“做一个电商平台”涉及用户、商品、订单、支付、物流、评价、库存光表就十几张做到一半发现关联查询写不动前端页面也来不及做。我一般建议选一个业务闭环短、实体关系清晰的场景比如“学生选课管理系统”“图书借阅管理系统”“实验室设备预约系统”。这类场景的实体通常不超过 6 个关系以一对多和一对一为主多对多只需要一张中间表就能解决。以“图书借阅管理系统”为例核心实体是读者、图书、借阅记录。读者和图书之间通过借阅记录形成多对多关系借阅记录本身还带有借出日期、应还日期、归还日期等属性。这个规模刚好能覆盖主键、外键、唯一约束、默认值、检查约束、事务、视图、存储过程这些课程设计需要体现的知识点又不会让工作量失控。选题还有一个容易被忽略的点业务规则要能翻译成数据库约束。比如“同一本书不能被同一个人同时借两次”这对应借阅记录表上读者编号图书编号归还日期的唯一约束其中归还日期为空表示未归还。如果业务规则说不清楚后面写 SQL 的时候就会反复改表结构这是血泪经验。2.2 用 PowerDesigner 画 CDM 和 PDM 的具体步骤PowerDesigner 在课程设计里的作用是先把概念模型画清楚再自动生成物理模型和建表 SQL。很多人跳过概念模型直接建表结果做到一半发现实体关系搞错了改起来非常痛苦。正确顺序是先画概念数据模型CDM检查实体关系是否覆盖了所有业务规则再转成物理数据模型PDM在 PDM 里补字段类型、约束和索引最后生成 SQL 脚本。具体操作路径如下。打开 PowerDesigner新建 Model选择 Conceptual Data Model然后在右侧工具栏拖出 Entity 和 Relationship。实体命名用中文但 Code 列填英文表名这样后面生成的 SQL 表名是英文的避免中文表名带来的编码问题。关系类型根据业务确定一个读者可以有多条借阅记录所以读者和借阅记录是一对多一本书也可以有多条借阅记录所以图书和借阅记录也是一对多。PowerDesigner 会自动在“多”端生成外键。画完 CDM 后通过 Tools → Generate Physical Data Model 转成 PDM。在 PDM 里需要做几件事把主键的数据类型改成 int 并设置自增把日期字段改成 datetime给 ISBN 加唯一约束给借阅状态加检查约束比如只允许“借出”“归还”“逾期”三个值。这些约束在 CDM 阶段不需要体现但在 PDM 阶段必须补上否则生成的建表语句缺少完整性保护。最后通过 Database → Generate Database 生成 SQL 脚本。生成时注意勾选“Generate primary key”“Generate foreign key”“Generate check constraint”字符集选 Chinese_PRC_CI_AS。生成的脚本不要直接执行先检查一遍外键的级联规则。默认情况下 PowerDesigner 生成的外键是 Restrict意味着有借阅记录的图书不能被删除这符合业务逻辑。如果误设成 Cascade删一本书会把所有借阅历史一起删掉这是典型的翻车点。2.3 从 PDM 到 SQL Server 建库建表的落地命令PowerDesigner 生成的 SQL 脚本可以直接在 SQL Server Management Studio 里执行但有几个细节需要手动调整。下面是一段典型的建表脚本以图书表和借阅记录表为例-- 创建数据库注意文件路径根据实际环境修改 CREATE DATABASE LibraryDB ON PRIMARY ( NAME LibraryDB_Data, FILENAME D:\SQLData\LibraryDB_Data.mdf, SIZE 10MB, MAXSIZE 200MB, FILEGROWTH 5MB ) LOG ON ( NAME LibraryDB_Log, FILENAME D:\SQLData\LibraryDB_Log.ldf, SIZE 5MB, MAXSIZE 100MB, FILEGROWTH 2MB ); GO USE LibraryDB; GO -- 图书表ISBN 唯一库存数量有检查约束 CREATE TABLE Book ( BookID INT IDENTITY(1,1) PRIMARY KEY, ISBN VARCHAR(20) NOT NULL UNIQUE, Title NVARCHAR(100) NOT NULL, Author NVARCHAR(50) NOT NULL, Publisher NVARCHAR(80), TotalCopies INT NOT NULL DEFAULT 1 CHECK (TotalCopies 0), AvailableCopies INT NOT NULL DEFAULT 1 CHECK (AvailableCopies 0), CONSTRAINT CK_AvailableNotExceedTotal CHECK (AvailableCopies TotalCopies) ); GO -- 借阅记录表外键关联读者和图书归还日期为空表示未归还 CREATE TABLE BorrowRecord ( RecordID INT IDENTITY(1,1) PRIMARY KEY, ReaderID INT NOT NULL, BookID INT NOT NULL, BorrowDate DATETIME NOT NULL DEFAULT GETDATE(), DueDate DATETIME NOT NULL, ReturnDate DATETIME NULL, Status VARCHAR(10) NOT NULL DEFAULT 借出 CHECK (Status IN (借出, 归还, 逾期)), CONSTRAINT FK_Borrow_Reader FOREIGN KEY (ReaderID) REFERENCES Reader(ReaderID), CONSTRAINT FK_Borrow_Book FOREIGN KEY (BookID) REFERENCES Book(BookID) ); GO -- 未归还的同一本书不能被同一读者重复借阅 CREATE UNIQUE INDEX UQ_ActiveBorrow ON BorrowRecord (ReaderID, BookID) WHERE ReturnDate IS NULL; GO这段脚本里有几个关键设计点。第一AvailableCopies TotalCopies这个检查约束保证了库存逻辑不会出现负数或超发。第二借阅记录表的状态字段用检查约束限定取值范围避免写入脏数据。第三UQ_ActiveBorrow是一个筛选唯一索引只对ReturnDate IS NULL的行生效这样已归还的记录不会阻止同一读者再次借阅同一本书。这个索引是业务规则“同一本书不能同时被同一人借两次”的直接翻译比在应用层写判断可靠得多。参数方面数据库文件初始大小设 10MB 对课程设计足够日志文件 5MB 也够用。如果 SQL Server 安装在 C 盘而 D 盘不存在需要把路径改成实际存在的目录否则建库会报“操作系统错误 3”。字符集用默认的 Chinese_PRC_CI_AS 即可排序规则影响中文比较课程设计一般不需要改。3. 用 Visual Studio 把增删改查做成能演示的界面3.1 连接 SQL Server 的两种方式与选择理由Visual Studio 里连接 SQL Server 常见两种方式一种是直接用 SqlConnection 写 ADO.NET 代码另一种是用 Entity Framework 做 ORM 映射。课程设计里我建议用 ADO.NET原因是它把 SQL 语句暴露在代码里答辩时能清楚展示“这条查询对应哪张表、用了什么条件”而 Entity Framework 生成的 SQL 是隐式的老师问起来不好解释。另外 ADO.NET 对事务的控制更直接借书和还书需要同时更新借阅记录和图书库存用 SqlTransaction 包起来最直观。连接字符串的写法// 使用 Windows 身份验证连接本地 SQL Server string connStr Serverlocalhost;DatabaseLibraryDB;Integrated SecurityTrue;;如果 SQL Server 配置了混合验证模式也可以写成User Idsa;Password你的密码;。注意连接字符串里的Server可以是localhost、.或(local)三者等价。如果报“无法打开登录所请求的数据库”先检查 SQL Server 服务是否启动再检查数据库名是否拼错。3.2 借书与还书的事务处理代码借书操作需要做三件事插入一条借阅记录、把图书的可借数量减一、检查可借数量是否大于零。这三步必须在一个事务里完成否则并发情况下可能出现超借。下面是核心代码public bool BorrowBook(int readerId, int bookId) { using (SqlConnection conn new SqlConnection(connStr)) { conn.Open(); using (SqlTransaction tran conn.BeginTransaction()) { try { // 第一步检查可借数量用 UPDLOCK 防止并发超借 string checkSql SELECT AvailableCopies FROM Book WITH (UPDLOCK) WHERE BookID BookID; SqlCommand checkCmd new SqlCommand(checkSql, conn, tran); checkCmd.Parameters.AddWithValue(BookID, bookId); int available (int)checkCmd.ExecuteScalar(); if (available 0) { tran.Rollback(); return false; // 库存不足借书失败 } // 第二步插入借阅记录应还日期为借出日期加 30 天 string insertSql INSERT INTO BorrowRecord (ReaderID, BookID, BorrowDate, DueDate, Status) VALUES (ReaderID, BookID, GETDATE(), DATEADD(DAY, 30, GETDATE()), 借出); SqlCommand insertCmd new SqlCommand(insertSql, conn, tran); insertCmd.Parameters.AddWithValue(ReaderID, readerId); insertCmd.Parameters.AddWithValue(BookID, bookId); insertCmd.ExecuteNonQuery(); // 第三步可借数量减一 string updateSql UPDATE Book SET AvailableCopies AvailableCopies - 1 WHERE BookID BookID; SqlCommand updateCmd new SqlCommand(updateSql, conn, tran); updateCmd.Parameters.AddWithValue(BookID, bookId); updateCmd.ExecuteNonQuery(); tran.Commit(); return true; } catch (Exception ex) { tran.Rollback(); throw new Exception(借书失败 ex.Message); } } } }这段代码的关键在WITH (UPDLOCK)这个表提示。它在对 Book 表加更新锁阻止其他事务同时读取同一行并修改库存。如果没有这个锁两个用户同时借同一本书都读到 AvailableCopies 为 1都执行减一结果库存变成 -1这就是典型的并发超借。加上 UPDLOCK 后第二个事务会等待第一个事务提交后才能读取读到的就是减一后的 0从而正确拒绝。还书操作逻辑类似但方向相反更新借阅记录的归还日期和状态同时把可借数量加一。注意还书时要检查这条借阅记录是否存在且未归还避免重复还书导致库存虚增。3.3 用 DataGridView 做数据展示与参数化查询课程设计的界面不需要多漂亮但增删改查要能演示。用 Visual Studio 的 Windows Forms拖一个 DataGridView 和一个查询按钮绑定数据源即可。查询代码用参数化查询防止 SQL 注入private void LoadBooks(string keyword) { string sql SELECT BookID, ISBN, Title, Author, TotalCopies, AvailableCopies FROM Book WHERE Title LIKE Keyword OR Author LIKE Keyword; using (SqlDataAdapter adapter new SqlDataAdapter(sql, connStr)) { adapter.SelectCommand.Parameters.AddWithValue(Keyword, % keyword %); DataTable dt new DataTable(); adapter.Fill(dt); dataGridView1.DataSource dt; } }参数化查询的要点是SQL 语句里用Keyword占位实际值通过Parameters.AddWithValue传入不要用字符串拼接。字符串拼接的写法WHERE Title LIKE % keyword %在输入包含单引号时会报错更严重的是可以被注入 OR 11这样的条件绕过筛选。课程设计答辩时老师经常问“你怎么防止 SQL 注入”参数化查询就是标准答案。DataGridView 绑定 DataTable 后列名默认显示英文。可以在代码里设置dataGridView1.Columns[Title].HeaderText 书名;来改成中文。如果查询结果为空DataGridView 会显示空白可以在界面上加一个 Label 显示“未找到匹配记录”提升演示效果。4. 避坑与排查课程设计里最容易翻车的 5 个点4.1 现象PowerDesigner 生成的 SQL 执行报“外键引用无效表”原因通常是 PDM 里表的生成顺序不对或者外键引用的表没有被包含在生成脚本里。PowerDesigner 默认按表名字母顺序生成如果 BorrowRecord 排在 Reader 前面而 BorrowRecord 有指向 Reader 的外键建表就会失败。解决方式有两种一是在 Generate Database 的 Options 里勾选“Generate foreign key after all tables”让所有表先建完再统一加外键二是手动调整脚本顺序把被引用的表放在前面。我一般用第二种因为生成的脚本更直观答辩时也方便讲解表之间的关系。4.2 现象Visual Studio 连接数据库报“用户登录失败”如果用的是 Windows 身份验证检查当前 Windows 账户是否有 SQL Server 的登录权限。在 SSMS 里展开“安全性 → 登录名”看当前账户是否在列表里。如果不在需要手动添加并授予 db_owner 权限。如果用 sa 账户检查是否启用了混合验证模式右键服务器 → 属性 → 安全性 → 勾选“SQL Server 和 Windows 身份验证模式”然后重启 SQL Server 服务。还有一个隐蔽的原因连接字符串里写的是Serverlocalhost但 SQL Server 配置的是命名实例比如localhost\SQLEXPRESS。这种情况下需要把 Server 改成localhost\SQLEXPRESS或者.\SQLEXPRESS。判断方法是在 SSMS 的连接窗口看服务器名称栏里显示的是什么。4.3 现象借书时库存变成负数前面讲过这是并发超借导致的。除了加 UPDLOCK还有一种做法是在 Book 表的 AvailableCopies 字段上加检查约束CHECK (AvailableCopies 0)。这样即使并发导致减到负数数据库也会拒绝执行事务回滚。但检查约束只能兜底不能替代 UPDLOCK因为约束报错时用户体验很差而且高并发下会频繁回滚。更稳妥的做法是把检查约束和 UPDLOCK 结合使用UPDLOCK 保证正常流程不超借检查约束保证异常情况下数据不会脏。课程设计里并发量不大但答辩时老师可能会问“如果两个人同时借同一本书会怎样”这时候能讲清楚 UPDLOCK 和检查约束的双重保护就是加分项。4.4 现象日期字段插入报“将 varchar 数据类型转换为 datetime 数据类型时失败”这种错误通常是因为日期字符串格式和 SQL Server 的日期格式不匹配。比如代码里写2024-01-15在大多数情况下没问题但如果 SQL Server 的默认语言设置是英语01/15/2024可能被解析成 1 月 15 日或 15 月 1 日取决于具体设置。解决方式是统一用yyyy-MM-dd格式或者在 SQL 里用CONVERT(datetime, 2024-01-15, 120)显式指定格式。更推荐的做法是直接在 SQL 里用GETDATE()和DATEADD计算日期避免从 C# 传日期字符串。比如应还日期用DATEADD(DAY, 30, GETDATE())生成就不存在格式问题。4.5 现象DataGridView 修改数据后数据库没更新DataGridView 绑定 DataTable 后用户在界面上修改单元格内容DataTable 里的数据会变但数据库不会自动同步。需要手动调用 SqlDataAdapter 的 Update 方法并且要配置 InsertCommand、UpdateCommand、DeleteCommand。很多人只配了 SelectCommand所以查询能显示修改不生效。最简单的做法是用 SqlCommandBuilder 自动生成增删改命令SqlDataAdapter adapter new SqlDataAdapter(SELECT * FROM Book, connStr); SqlCommandBuilder builder new SqlCommandBuilder(adapter); DataTable dt new DataTable(); adapter.Fill(dt); dataGridView1.DataSource dt; // 用户修改后调用 adapter.Update(dt);注意 SqlCommandBuilder 要求 SELECT 语句里包含主键列否则无法生成 Update 和 Delete 命令。如果 Book 表的主键是 BookIDSELECT 语句里必须包含 BookID。另外如果表有自增列InsertCommand 会自动忽略自增列不需要手动处理。5. 把设计文档写成答辩能用的技术叙事5.1 文档结构不是目录堆砌而是决策链“数据库课程设计(5).doc”这份文档的价值不在于格式多规范而在于它能不能回答三个问题为什么选这个业务场景、为什么这样设计表结构、为什么用这些约束和事务。我一般把文档分成四块需求与业务规则、概念模型与逻辑模型、物理实现与关键代码、测试与问题记录。每块之间要有推导关系比如业务规则“同一本书不能同时被同一人借两次”推导出借阅记录表上的筛选唯一索引这个索引又推导出借书代码里需要处理唯一约束冲突的异常。文档里要放 E-R 图但不要只放图不解释。E-R 图下面用一段话说明每个实体的主键是什么、实体之间的关系是一对多还是多对多、多对多关系是怎么拆解的。PowerDesigner 导出的 PDM 截图也可以放但重点是标注哪些字段加了约束、约束的业务含义是什么。5.2 测试用例要覆盖边界而不是只走正常流程课程设计的测试部分经常被写成“点击查询按钮显示数据”这种正常流程。但答辩时老师更关心边界情况借书时库存为 0 会怎样、还书时重复还同一本书会怎样、查询时输入单引号会怎样、删除有借阅记录的图书会怎样。这些边界用例才是体现设计完整性的地方。我一般会准备一张测试表列出测试项、输入、预期结果、实际结果。比如“借阅库存为 0 的图书”预期结果是提示“库存不足”并回滚事务“删除有未归还记录的图书”预期结果是外键约束阻止删除并提示“请先归还”。这些用例不需要写自动化测试脚本手动执行一遍并截图记录即可但文档里要写清楚测试结论。5.3 答辩时被问到“为什么不用 MySQL”怎么答这个问题几乎每场数据库课程设计答辩都会出现。回答的思路不是比较哪个数据库更好而是说明选择 SQL Server 的具体理由课程教学用的是 SQL Server实验环境已经配置好SQL Server 的 T-SQL 语法和 SSMS 工具链对课程设计里的存储过程、触发器、事务支持更直观PowerDesigner 对 SQL Server 的 PDM 生成支持更成熟。如果老师追问“如果换成 MySQL 要改什么”可以回答自增列从 IDENTITY 改成 AUTO_INCREMENT日期函数从 GETDATE() 改成 NOW()检查约束在 MySQL 8.0 之前不支持需要用触发器替代。这样回答既展示了知识面又不会陷入无意义的数据库优劣争论。5.4 一个让文档加分的习惯记录每次改表的原因做课程设计的过程中表结构几乎不可能一次定稿。比如一开始借阅记录表没有 Status 字段后来发现需要区分“借出”“归还”“逾期”就加了这个字段。如果文档里只放最终的表结构老师看不出设计过程。我习惯在文档末尾加一个“设计变更记录”表格列出每次改动的日期、改动内容、改动原因。比如“2024-01-10BorrowRecord 表增加 Status 字段原因需要支持逾期查询和状态筛选”。这个习惯花不了多少时间但能让答辩时的技术叙事更完整也显得设计过程是迭代出来的而不是拍脑袋定的。最后一章不写总结说一个我自己的习惯每次做完课程设计我会把建库脚本、核心代码和文档放在同一个文件夹里用 Git 做一次提交提交信息写清楚“完成借书事务和并发测试”。这样下次做类似项目时直接翻出这个提交就能复用建表脚本和事务模板不用从头再来。数据库课程设计看起来是一次性作业但里面的事务处理、约束设计、参数化查询这些套路在后面的实际项目里反复出现。把这次做扎实后面能省很多事。希望帮到你。本文还有配套的精品资源点击获取