简介:这是一份以高校教务管理系统为背景的数据库课程设计报告,面向数据库初学者、课程设计学生及需要快速搭建教务类数据模型的技术人员。报告从需求分析出发,梳理了学生学籍、教学、教师、教材四大功能模块,并给出全局E-R图、关系模式及数据字典。其中,student、teacher、book、class、stc、boocla等表结构均配有字段类型、主键与外键约束说明,涵盖学号、姓名、性别、专业编码、课程号、教师编号、教材编号等关键属性,能够直观展示关系数据库的设计规范。数据字典部分对每个字段的存储格式与约束做了逐项解释,便于读者理解表间关联与数据完整性设计。系统实现部分则描述了管理员登录、信息查询、添加与删除等操作界面,使读者可以对照报告还原一个可运行的基础教务管理系统。资源包共1个PDF文件,大小1.28MB,内容精炼、便于收藏阅读。该文档已被233人学习下载,适合作为课程设计、期末答辩或毕业设计的参考模板,能帮助读者快速掌握从需求梳理到数据库建模再到系统实现的完整流程。
1. 数据库课程设计拿这份教务管理系统报告:E-R图、建表SQL和ASP增删改查一次给全
这是一份2011年的大学课程设计报告,但对今天正在赶数据库课设的人来说,它依然比很多“XX系统全套源码”有用。报告把教务管理系统从需求分析、功能模块图、全局E-R图、关系模式、数据字典一直写到可运行的ASP页面代码,学生学籍、教师信息、教学课程、教材管理四块全部覆盖,管理员登录后能增删改查,学生登录后能查资料和课表。这意味着你拿到的不只是一篇讲解,而是一套能照着改的完整骨架,建表语句和页面关键代码都在里面。下面按我拆项目的习惯,把设计思路、表结构、核心代码和翻新时会踩的坑逐层说清楚。
2. 教务管理系统结构拆解:四大模块怎么落到六张业务表上
课程设计报告最容易被忽略但最值钱的部分,不是后面的代码,而是前面的需求分析和数据库设计。评审老师问得最多的“为什么有这张表”“这张表为什么有这些字段”,答案全在这一段。
2.1 功能模块图背后的设计思路:为什么拆成四个管理区
报告把整个系统切成四块:学生学籍管理、教学管理、教师管理、教材管理。这不是拍脑袋分的,而是按数据实体来的。学生学籍管学生信息的增删改查;教学管理管课程信息查询、添加课程、替学生选课;教师管理管教师的增删改查;教材管理管教材的查询、添加、修改。每一块都对应至少一张物理表,界面导航也顺着这个结构走,管理员登录后默认进“学生学籍管理”,点链接切换到其他页面。
这种拆法对课程设计有一个实际好处:模块和表一一对应,画功能模块图、写需求分析、做界面跳转都顺。更重要的是,答辩时老师问“模块怎么来的”,你可以直接回答“模块是跟着业务实体走的”,这就是需求分析和数据库设计之间那条最直接的线。
2.2 六张业务表的字段设计:主键、外键与数据类型明细
报告给出了六张核心表,我先把它们的定位列清楚:
| 表名 | 对应模块 | 关键字段 | 主键 |
|---|---|---|---|
| student | 学生学籍管理 | 学号、姓名、密码、性别、出生日期、入学日期、专业编码、电话、籍贯 | studentnum |
| teacher | 教师管理 | 教师编号、姓名、密码、性别、出生日期、部门编号、职称、电话、籍贯 | teachernum |
| class | 教学管理 | 课程号、课程名、考试/考查、学时、学分 | classnum |
| book | 教材管理 | 教材编号、教材名称、版本、发行码、主编、单价、页码 | booknum |
| stc | 选课关联 | 课程号、学号、教师编号 | 三个字段联合主键 |
| boocla | 课程选用教材关联 | 课程号、教材编号 | 两个字段联合主键 |
student和teacher本质上结构对称,都有一组出生年月字段,这对应E-R图里的两个强实体。class和book是课程、教材两个独立实体。真正有意思的是stc和boocla:它们是把“选课”和“选用教材”两个多对多联系变成的中间表。比如stc里一个学生对应一门课的一位老师,学生和课程是多对多,课程和教师也是多对多,所以选课关系必须用联合主键(studentnum, teachernum, classnum)来保证唯一。
2.3 建表代码:字段、约束和注释一次到位
报告源程序清单里给了完整建表语句,我把它整理成下面这份可直接执行的版本,字段名和长度保持原样:
-- 学生主表:学号为主键,性别用CHECK约束 CREATE TABLE student ( studentnum VARCHAR(10) PRIMARY KEY, -- 学号 studentname VARCHAR(10) NOT NULL, -- 姓名 ssecret VARCHAR(10) NOT NULL, -- 登录密码 sex VARCHAR(10) CHECK (sex IN ('男','女')), stuyear VARCHAR(10), -- 出生年 stumon VARCHAR(10), -- 出生月 studay VARCHAR(10), -- 出生日 inyear VARCHAR(10), -- 入学年 inmon VARCHAR(10), -- 入学月 inday VARCHAR(10), -- 入学日 specialnum VARCHAR(10) NOT NULL, -- 专业编码 phone VARCHAR(11), -- 联系电话 city VARCHAR(20) -- 籍贯 ); -- 教师主表:教师编号为主键,部门编号对应当前课程设计里的classnum CREATE TABLE teacher ( teachernum VARCHAR(10) PRIMARY KEY, -- 教师编号 teachername VARCHAR(10) NOT NULL, -- 姓名 ssecret VARCHAR(10) NOT NULL, -- 登录密码 sex VARCHAR(10) CHECK (sex IN ('男','女')), teayear VARCHAR(10), -- 出生年 teamon VARCHAR(10), -- 出生月 teaday VARCHAR(10), -- 出生日 classnum VARCHAR(10) NOT NULL, -- 部门/所属单位编号 position VARCHAR(10) NOT NULL, -- 职称 phone VARCHAR(11), -- 电话 city VARCHAR(20) -- 籍贯 ); -- 课程表:考试方式限定为考试或考查 CREATE TABLE class ( classnum VARCHAR(10) PRIMARY KEY, -- 课程号 classname VARCHAR(10) NOT NULL, -- 课程名 exam VARCHAR(10) CHECK (exam IN ('考试','考查')), knowledge VARCHAR(10), -- 学时 credits VARCHAR(10) -- 学分 ); -- 教材表:教材编号为主键,发行码必填 CREATE TABLE book ( booknum VARCHAR(10) PRIMARY KEY, -- 教材编号 bookname VARCHAR(20) NOT NULL, -- 教材名称 edition VARCHAR(20), -- 版本 number VARCHAR(10) NOT NULL, -- 发行码 editor VARCHAR(10), -- 主编 rate VARCHAR(10) NOT NULL, -- 单价 pagenum VARCHAR(10) -- 页码 );写完之后要重点检查两点:一是字段长度是否够用,后面避坑章会专门说varchar(10)的隐患;二是性别、考试方式这类枚举字段有没有加CHECK约束。报告里用CHECK限制“男/女”“考试/考查”,这是当时SQL Server 2000的常见做法,评审老师看到约束会觉得你对完整性有概念。学时和学分用的是varchar而不是int,这在2011年的报告里很常见,改造成现代版本时建议换成数值类型。
2.4 关联表stc和boocla:多对多关系怎么用外键锁死
选课和选用教材是多对多关系,必须用中间表承载。报告里的做法是各建一张关联表,联合主键保证同一组合不重复,外键保证引用的行一定存在:
-- 选课表:一个学生选一门课由一位老师教 CREATE TABLE stc ( classnum VARCHAR(10) NOT NULL, -- 课程号 studentnum VARCHAR(10) NOT NULL, -- 学号 teachernum VARCHAR(10) NOT NULL, -- 教师编号 PRIMARY KEY (studentnum, teachernum, classnum), FOREIGN KEY (studentnum) REFERENCES student(studentnum), FOREIGN KEY (teachernum) REFERENCES teacher(teachernum), FOREIGN KEY (classnum) REFERENCES class(classnum) ); -- 课程选用教材表:一门课可以选多本教材 CREATE TABLE boocla ( classnum VARCHAR(10) NOT NULL, -- 课程号 booknum VARCHAR(10) NOT NULL, -- 教材编号 PRIMARY KEY (classnum, booknum), FOREIGN KEY (booknum) REFERENCES book(booknum), FOREIGN KEY (classnum) REFERENCES class(classnum) );注意stc的联合主键顺序。报告原文写的是(studentnum, teachernum, classnum),意思是同一个学生、同一位老师、同一门课只能出现一次。实际查询时如果经常按课程维度过滤,也可以把classnum放前面建索引,这是后话。boocla的逻辑更简单,一门课配一本或多本教材,书和课的组合不能重复。两张关联表把E-R图里的“选课”和“选用”联系落成了物理结构,这也是从概念模型到关系模式最标准的映射方式。
2.5 数据字典:把每个字段变成可交付的说明书
报告第三部分是数据字典,逐表列出字段、类型、是否为空和约束。课程设计里数据字典不是凑字数,它是你后续写代码、写接口、做测试的统一口径。比如student里phone是VARCHAR(11),是因为手机号最长11位;city是VARCHAR(20),籍贯全称基本够用。我把student表的数据字典按报告原意整理成下面这个格式:
| 字段 | 类型 | 允许空 | 约束与说明 |
|---|---|---|---|
| studentnum | varchar(10) | 否 | 主键,学号 |
| studentname | varchar(10) | 否 | 姓名 |
| ssecret | varchar(10) | 否 | 登录密码 |
| sex | varchar(10) | 是 | check(男/女) |
| stuyear/stumon/studay | varchar(10) | 是 | 出生年月日 |
| inyear/inmon/inday | varchar(10) | 是 | 入学年月日 |
| specialnum | varchar(10) | 否 | 专业编码 |
| phone | varchar(11) | 是 | 电话 |
| city | varchar(20) | 是 | 籍贯 |
我一般会把数据字典和建表代码放在一起维护,表结构一改,字典同步改,这样交作业或者接手项目时不用对着SQL猜字段含义。报告里teacher、book、class的字典结构类似,就不再重复贴表,核心是保持“字段名—类型—约束—用途”四列齐全。
3. 把表结构变成能跑的后台:ASP连接SQL Server的三种关键写法
报告的系统实现部分用的是ASP搭配SQL Server 2000,页面由Dreamweaver CS3生成。这套技术栈现在看确实老,但增删改查的写法逻辑放到今天依然能读,而且恰好是“数据库课程设计”最常被要求展示的部分。
3.1 conn.asp:一个连接串搞定所有页面
报告把所有页面共用的数据库连接放在Connections/conn.asp里,这是ASP站点的标准做法。核心代码只有一段:
<% Dim MM_conn_STRING MM_conn_STRING = "Provider=SQLOLEDB;data source=(local);initial catalog=teachers;uid=sa;pwd=;" %>这段代码的意思是:用SQLOLEDB这个OLE DB提供程序连接本机SQL Server,数据库名是teachers,登录账号sa,密码为空。data source=(local)表示连接本机默认实例,如果你用的是命名实例,要写成“服务器名\实例名”这样的格式。initial catalog指定数据库名,和后面页面里“select * from student”操作的库对应。uid=sa;pwd=是SQL Server混合认证的登录方式。
实际复现时有两个地方要改:一是pwd要填真实密码,二是如果SQL Server实例不是默认实例,data source要改成具体实例名。这个文件被全站引用,所以只要改一处,所有页面的连接就都切换过来了。
3.2 添加学生:ADODB.Command做参数化插入
报告中添加学生页面的核心逻辑是用ADODB.Command对象执行INSERT语句,而不是简单拼接字符串,这点放在2011年是相当规范的做法:
<% Set MM_editCmd = Server.CreateObject("ADODB.Command") MM_editCmd.ActiveConnection = MM_conn_STRING MM_editCmd.CommandText = "INSERT INTO dbo.student (studentnum, studentname, ssecret, sex, stuyear, stumon, studay, inyear, inmon, inday, specialnum, phone, city) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" MM_editCmd.Prepared = true MM_editCmd.Parameters.Append MM_editCmd.CreateParameter("param1", 201, 1, 10, Request.Form("studentnum")) MM_editCmd.Parameters.Append MM_editCmd.CreateParameter("param2", 201, 1, 10, Request.Form("studentname")) MM_editCmd.Parameters.Append MM_editCmd.CreateParameter("param3", 201, 1, 10, Request.Form("ssecret")) MM_editCmd.Parameters.Append MM_editCmd.CreateParameter("param4", 201, 1, 10, Request.Form("sex")) MM_editCmd.Parameters.Append MM_editCmd.CreateParameter("param5", 201, 1, 10, Request.Form("stuyear")) MM_editCmd.Parameters.Append MM_editCmd.CreateParameter("param6", 201, 1, 10, Request.Form("stumon")) MM_editCmd.Parameters.Append MM_editCmd.CreateParameter("param7", 201, 1, 10, Request.Form("studay")) MM_editCmd.Parameters.Append MM_editCmd.CreateParameter("param8", 201, 1, 10, Request.Form("inyear")) MM_editCmd.Parameters.Append MM_editCmd.CreateParameter("param9", 201, 1, 10, Request.Form("inmon")) MM_editCmd.Parameters.Append MM_editCmd.CreateParameter("param10", 201, 1, 10, Request.Form("inday")) MM_editCmd.Parameters.Append MM_editCmd.CreateParameter("param11", 201, 1, 10, Request.Form("specialnum")) MM_editCmd.Parameters.Append MM_editCmd.CreateParameter("param12", 201, 1, 10, Request.Form("phone")) MM_editCmd.Parameters.Append MM_editCmd.CreateParameter("param13", 201, 1, 10, Request.Form("city")) MM_editCmd.Execute MM_editCmd.ActiveConnection.Close Response.Write("<script>alert('添加成功!');window.location.href='index_stu.asp';</script>") %>这里CreateParameter的第一个参数是参数名,第二个201表示adLongVarChar类型,第三个1表示允许输入长度,第四个10是字段最大长度,第五个是实际传入的值。Prepared=true的作用是让SQL Server预编译这条语句,同样的INSERT反复执行时性能更好,更重要的是参数化能避免用户输入直接拼进SQL。对课程设计来说,你能说清“参数化防止SQL注入”,答辩印象分立刻不一样。
3.3 修改学生:UPDATE带WHERE,避免整表被改
修改页面modify_stu.asp同样用Command对象,但注意它的参数顺序和WHERE位置:
<% MM_editCmd.CommandText = "UPDATE dbo.student SET studentname = ?, ssecret = ?, sex = ?, stuyear = ?, stumon = ?, studay = ?, inyear = ?, inmon = ?, inday = ?, specialnum = ?, phone = ?, city = ? WHERE studentnum = ?" MM_editCmd.Parameters.Append MM_editCmd.CreateParameter("param1", 201, 1, 10, Request.Form("studentname")) MM_editCmd.Parameters.Append MM_editCmd.CreateParameter("param2", 201, 1, 10, Request.Form("ssecret")) MM_editCmd.Parameters.Append MM_editCmd.CreateParameter("param3", 201, 1, 10, Request.Form("sex")) MM_editCmd.Parameters.Append MM_editCmd.CreateParameter("param4", 201, 1, 10, Request.Form("stuyear")) MM_editCmd.Parameters.Append MM_editCmd.CreateParameter("param5", 201, 1, 10, Request.Form("stumon")) MM_editCmd.Parameters.Append MM_editCmd.CreateParameter("param6", 201, 1, 10, Request.Form("studay")) MM_editCmd.Parameters.Append MM_editCmd.CreateParameter("param7", 201, 1, 10, Request.Form("inyear")) MM_editCmd.Parameters.Append MM_editCmd.CreateParameter("param8", 201, 1, 10, Request.Form("inmon")) MM_editCmd.Parameters.Append MM_editCmd.CreateParameter("param9", 201, 1, 10, Request.Form("inday")) MM_editCmd.Parameters.Append MM_editCmd.CreateParameter("param10", 201, 1, 10, Request.Form("specialnum")) MM_editCmd.Parameters.Append MM_editCmd.CreateParameter("param11", 201, 1, 10, Request.Form("phone")) MM_editCmd.Parameters.Append MM_editCmd.CreateParameter("param12", 201, 1, 10, Request.Form("city")) MM_editCmd.Parameters.Append MM_editCmd.CreateParameter("param13", 200, 1, 10, Request.Form("MM_recordId")) MM_editCmd.Execute %>UPDATE语句里WHERE studentnum = ?是最后那个参数,类型是200即adVarChar,对应从查询字符串传来的MM_recordId。这个顺序不能乱,因为ASP的Parameters.Append是按位置跟CommandText里的问号绑定的。报告明确用学号作定位条件,而且只允许改姓名、密码、电话等字段,学号本身不能改,这是主键不可变原则的正确体现。
3.4 学生端登录:Session记录当前用户
学生入口的登录逻辑是student_index.asp,用户在页面输入学号和密码,服务端用Session保存登录状态。报告里给出的响应方式是用弹窗提示“登录成功”后跳转,会话保持则靠Session("username"):
<% If Session("username") <> "" Then Recordset1__MMColParam = Session("username") End If Set Recordset1_cmd = Server.CreateObject("ADODB.Command") Recordset1_cmd.ActiveConnection = MM_conn_STRING Recordset1_cmd.CommandText = "SELECT * FROM dbo.student WHERE studentnum = ?" Recordset1_cmd.Prepared = true Recordset1_cmd.Parameters.Append Recordset1_cmd.CreateParameter("param1", 200, 1, 10, Recordset1__MMColParam) Set Recordset1 = Recordset1_cmd.Execute %>这段代码的用途是:登录成功后,后续页面从Session里拿学号,再根据学号查出学生全部资料。用Session的好处是学生每打开一个页面不需要重新输入密码,但要注意Session在ASP里默认有超时时间,用户长时间不操作会被登出,跳回登录页。报告里学生能查个人课表、改密码、改电话和籍贯,都是建立在这个登录态之上的。
4. 让查询页面真正能查:模糊搜索拼接与每页十行的分页逻辑
报告的管理员查询页面index_stu.asp是功能最集中的一个页面,它同时做了两件事:把表单里一堆条件拼成SQL的WHERE子句,再把结果按每页10条分页输出。这两块代码放在一起,几乎是所有ASP+SQL Server课设的标配,值得拆开讲透。
4.1 万能搜索:表单字段与SQL条件的拼装
管理员在页面上输入学号、姓名、性别、入学年等条件,点查找后系统把这些字段全部拼进一个SELECT语句。报告里的核心写法是每个字段都用LIKE匹配,空值则不参与过滤:
<% studentnum = Request.Form("studentnum") studentname = Request.Form("studentname") sex = Request.Form("sex") Set rs = Server.CreateObject("ADODB.Recordset") sql = "SELECT * FROM student WHERE 1=1" If studentnum <> "" Then sql = sql & " AND studentnum LIKE '%" & studentnum & "%'" End If If studentname <> "" Then sql = sql & " AND studentname LIKE '%" & studentname & "%'" End If If sex <> "" Then sql = sql & " AND sex = '" & sex & "'" End If rs.Open sql, conn, 1, 3 %>这里“WHERE 1=1”是拼接查询里非常实用的写法,它保证后面每个AND都能直接追加,不用费心判断前面是否已有条件,代码结构就干净很多。LIKE '%值%'实现的是包含匹配,适合学号、姓名这种用户记不全完整值的场景;性别这种枚举字段用等号更准确。
需要提醒的是,报告原文把所有字段都拼了LIKE,包括出生年、入学月这类数值型字段,这样不是不行,但性能上有浪费。我一般会把学号和姓名保留LIKE,把性别、专业编码改成等值匹配,既能满足搜索需求,也让SQL更合理。真正干活的时候,这种多条件组合查询还要考虑索引,字段前面加%会让索引失效,数据量上来会越来越慢,课程设计阶段通常不需要优化到这个程度。
4.2 分页:Recordset自带的分页机制
报告里分页逻辑用Recordset自带的分页属性实现,每页10条:
<% Const maxperpage = 10 Dim currentpage rs.PageSize = maxperpage currentpage = Request("page") If currentpage = "" Or Not IsNumeric(currentpage) Then currentpage = 1 Else currentpage = CLng(currentpage) If currentpage < 1 Then currentpage = 1 ElseIf currentpage > rs.PageCount Then currentpage = rs.PageCount End If End If rs.AbsolutePage = currentpage Dim i i = 0 Do While i < maxperpage And Not rs.EOF i = i + 1 ' 这里输出当前行数据 rs.MoveNext Loop %>rs.PageSize设定每页行数,rs.AbsolutePage跳转到指定页。分页显示时需要判断总页数,报告用总记录数除以PageSize并向上取整来算总页数,最后再画上一页、下一页的链接。这套机制的坑在于:如果查询结果不够一页,rs.PageCount可能是0,必须先处理currentpage=0的情况,否则会报错。报告里已经写了If currentpage < 1 Then currentpage = 1来兜底。
4.3 老代码里的隐患:拼接SQL与SQL注入
第4.1节的拼接写法有一个绕不过去的问题:用户输入直接进SQL,存在SQL注入风险。比如学号框里输入一段“' OR '1'='1'”就会破坏原语句结构。对这种老代码,我的习惯是给出一个参数化改造版本,用于说明正确的做法:
<% Set cmd = Server.CreateObject("ADODB.Command") cmd.ActiveConnection = MM_conn_STRING sql = "SELECT * FROM student WHERE 1=1 AND studentnum LIKE ? AND studentname LIKE ?" cmd.CommandText = sql cmd.Parameters.Append cmd.CreateParameter("param1", 201, 1, 50, "%" & studentnum & "%") cmd.Parameters.Append cmd.CreateParameter("param2", 201, 1, 50, "%" & studentname & "%") Set rs = cmd.Execute %>把LIKE匹配值本身也拼上%,再作为参数传进去,既保留模糊查询,又避免用户输入变成可执行SQL。这就是第3章已经用过的ADODB.Command参数化思路,多花十分钟改造,能让你的课设从“能跑”上升到“写法安全”,评审老师问到这层也不慌。
5. 翻新这份老项目时最容易踩的坑:外键笔误、明文密码与2000兼容性
把这份报告当参考资料用时,最怕的不是代码老,而是照着原文抄的时候翻车。我整理了五个最典型的坑,每条都来自实际复现中会遇到的场景。
5.1 坑一:boocla的外键引用了不存在的course表
现象:报告关系模式部分写boocla时有“foreign key(coursenum) references course(course...”的字样,但全文里根本没有course表,只有class表。
原因:报告写作时把概念模型里的“课程实体”直接写成了course,物理表名却是class,两个名字混用了。
解决:以可执行的建表代码为准,boocla正确的关联对象是class表和book表:
CREATE TABLE boocla ( classnum VARCHAR(10) NOT NULL, booknum VARCHAR(10) NOT NULL, PRIMARY KEY (classnum, booknum), FOREIGN KEY (booknum) REFERENCES book(booknum), FOREIGN KEY (classnum) REFERENCES class(classnum) );这条血的教训是:文档里的关系模式和图可能滞后于代码,遇到冲突时一定要写条SQL验证哪个能跑通。我每次拿到课程设计资料,先把建表SQL丢进数据库执行一遍,能建起来的那份才是真的。
5.2 坑二:varchar(10)装不下真实数据
现象:studentname、classname、teachername这些关键字段长度只有10,插入“欧阳娜娜”这类四字以上姓名勉强,遇到“计算机科学与技术基础”这样的课程名直接报错“String or binary data would be truncated”。
原因:2011年的课程设计数据量小,示例数据都很短,字段长度是按示例倒推的,没有考虑真实数据。
解决:把核心业务字段调长,姓名用VARCHAR(20),课程名用VARCHAR(50),教材名用VARCHAR(100),专业编码用VARCHAR(20)。如果不想动建表语句,也可以用ALTER TABLE补:
ALTER TABLE student ALTER COLUMN studentname VARCHAR(20) NOT NULL; ALTER TABLE class ALTER COLUMN classname VARCHAR(50) NOT NULL; ALTER TABLE book ALTER COLUMN bookname VARCHAR(100) NOT NULL;5.3 坑三:密码字段ssecret是明文存储
现象:student表和teacher表的ssecret字段直接存密码原文,数据库里一查就能看到所有学生的登录密码。
原因:课程设计要求没提安全,报告也完全没处理加密。
解决:给出一个ASP端的MD5哈希方案,入库前先转换,登录比对哈希值。老ASP环境里最常用MD5函数,核心逻辑如下:
<% Function MD5Hash(input) Dim md5 md5 = Server.CreateObject("System.Security.Cryptography.MD5CryptoServiceProvider") Dim bytes, hash bytes = System.Text.Encoding.Default.GetBytes(input) hash = md5.ComputeHash(bytes) MD5Hash = Hex(hash) End Function %>实际项目里用BCrypt或SHA-256更稳,但在这个技术栈下MD5加盐已经比明文强很多。答辩时主动提一句“密码没有明文存储”,老师很难在这块挑毛病。
5.4 坑四:SQL Server 2000在现在的Windows上装不起来
现象:按报告原文用SQL Server 2000 Personal SP4,在现代操作系统上安装失败或服务起不来,连接串里的SQLOLEDB也经常被系统提示不受信任。
原因:SQL Server 2000是二十多年前的产品,安装程序对现有系统的兼容性很差,而且现在也很难拿到可用的安装介质。
解决:换成SQL Server 2019/2022 Express,把连接串改成新版兼容写法:
MM_conn_STRING = "Driver={ODBC Driver 17 for SQL Server};Server=localhost;Database=teachers;Uid=sa;Pwd=你的密码;"这种基于ODBC的方式绕开SQLOLEDB的兼容问题,建表语句里用的varchar、CHECK、外键在SQL Server 2019里依然全部支持,不需要改表结构。说白了,表结构没过期,过期的是连接方式。
5.5 坑五:ASP页面中文全部变问号
现象:在页面上输入“张三”,提交后数据库里变成“???”,读出来再显示也全是问号。
原因:页面没有声明字符集,或者数据库排序规则不支持中文。
解决:两步修复。第一步在ASP页面顶部加声明:
<%@ LANGUAGE="VBSCRIPT" CODEPAGE="936" %>同时让HTML页面统一用UTF-8或GB2312编码。第二步建表时明确排序规则:
CREATE DATABASE teachers COLLATE Chinese_PRC_CI_AS;这套组合在我实践中基本能解决中文乱码问题。如果你用的是SQL Server 2019,字符集选UTF-8也可以,只要连接串、页面、数据库三者编码一致。
6. 用这份报告做验收和扩展:一条SQL验证完整性,一个视图把选课变成报表
报告本身停在一个“能增删改查”的阶段,但既然你拿着这份资源复现,我建议多做两步,让整个系统从“能跑”变成“能验收”。
第一步是验证数据完整性。把建表SQL跑完后,先塞几条测试数据,然后分别检查boocla、stc里的外键是否真的拦住了非法引用:
-- 找出选了教材但教材表里不存在的记录,应为0行 SELECT b.classnum, b.booknum FROM boocla b LEFT JOIN book bk ON b.booknum = bk.booknum WHERE bk.booknum IS NULL; -- 找出选了课程但学号不存在于student表的记录,应为0行 SELECT s.studentnum FROM stc s LEFT JOIN student st ON s.studentnum = st.studentnum WHERE st.studentnum IS NULL;这两条查询是验证外键约束是否生效的标准方式。它们返回的每一行都代表一条“孤儿记录”,也就是破坏了引用完整性的脏数据。课程设计答辩时,你展示这两条SQL和“查询结果为空”的截图,说服力比空口说“我设计了外键”强得多。
第二步是加一个视图,把选课关联表变成老师能看懂的成绩报表。stc表只有三个编号,人没法直接读,视图可以把学生姓名、课程名、老师姓名拼在一起:
CREATE VIEW v_selected_course AS SELECT st.studentname, c.classname, t.teachername FROM stc JOIN student st ON stc.studentnum = st.studentnum JOIN class c ON stc.classnum = c.classnum JOIN teacher t ON stc.teachernum = t.teachernum;之后只要写“SELECT * FROM v_selected_course”就能看到一张完整的选课清单,不用每次写三表JOIN。这一步向评审展示的是:你理解视图的本质是“保存好的查询”,也理解关系表之间怎么关联。
如果还想继续往上加,常见的扩展是增加成绩表,把考试成绩挂到选课记录上;或者做课表冲突检测,同一学生同一时间不能选两门课。这些都不需要推翻原有六张表,加一张score表或用SQL判断时间重叠即可。做课设时,与其重写一个宏大的系统,不如把这份报告里已有的骨架吃透,再补一两个亮点,效率和效果都好得多。
从那回自己翻新老项目以后,我养成一个习惯:拿到任何课程设计资料,先验证数据字典和建表代码对不对得上,外键逐条跑一遍,再去看页面代码。这个顺序能省掉后面大量排错时间。希望这份教务管理系统报告也能帮你少走一段弯路。
本文还有配套的精品资源,点击获取