首页/新闻资讯/正文详情

软件工程课程设计实战:选课系统从需求分析到ODBC数据库开发

发布时间:2026/11/3 11:16:54 来源:云帆数科 栏目:资讯中心
软件工程课程设计实战:选课系统从需求分析到ODBC数据库开发
简介这份《软件工程课程设计指导书》面向计算机科学与技术专业的初学者与课程设计指导教师用于解决从需求分析到报告撰写缺少规范范例的问题帮助读者按软件工程思想完成一个小型系统的完整开发流程。压缩包内共1个doc文档约539KB内容以文字教程为主集中呈现选课系统的设计任务、字段要求、实验环境与考核标准。全书以选课系统为案例明确学生、教师、课程、成绩等字段要求以及登录、查询、选课、退课、成绩管理等功能目标并给出用例图、序列图、对象模型与状态图的文档撰写要求还附有ODBC数据源配置和C Builder 6.0入门操作指南便于边看边练。目前已有99人学习适合作为课程设计前期的任务书、文档模板与实施路线参考。1. 从一张“选课系统”题目开始这份指导书到底解决什么问题如果你手里只有一个“选课系统”题目却不知道该先画用例图还是先建 Access 表这份软件工程课程设计指导书就是冲着这个卡点来的。它把 10 学时上机拆成需求分析、软件设计、测试数据、源代码和书面报告几条线开发环境锁定 C Builder 6.0 与 Access 2000示例题目是学生最熟悉的选课系统。它适合要交课程设计的新手也适合想复现传统 C/S 数据库开发链路的开发者。指导书不是现成源码包而是一份把选题、建库、连接、报告和测试串起来的实践手册附录里还给了 ODBC 数据源和 C Builder 窗体连接的完整操作路径。拿到后先看报告结构再照着附录建 ODBC 数据源基本能把从建库到登录选课的骨架跑起来。2. 指导书骨架拆解从需求分析到源代码的交付清单课程设计最容易翻车的地方不是代码写不出而是做到一半发现报告缺图、测试数据不够、源代码和文档对不上。指导书把交付物拆成需求分析、软件设计、软件测试、源代码和报告几个块每个块都有明确的验收物。读这份指导书时不要把它当成“实验步骤说明”翻过去而要把它当成一张交付清单每一项最终都要落到文件、图、表或可运行界面上。课程设计的基本要求写得很直白了解面向对象开发过程与方法完成所要求的系统报告文档符合具体要求。这三句话对应三个验收面过程要有需求分析和设计图系统要能登录、查询、选课、退课、查成绩报告要能按章节交上去。成绩考核按书面报告、软件系统和考勤三项加权所以只把代码跑起来并不够报告里的图和数据同样是得分点。2.1 交付目录与报告章节怎么对应我一般会建议把课程设计目录按“文档、数据库、源码、测试数据、截图”分开而不是把所有文件堆在桌面。指导书里的报告章节可以作为目录骨架题目、报告人信息、课程设计目的、课程设计要求、课程设计内容、需求分析、软件设计、软件测试、源代码、系统评价、自我心得。报告人信息在模板里留占位符提交前替换成自己的信息不要把真实姓名学号直接写进示例文件。下面这张表适合拿来对照交付物避免报告写完了却发现少图少表。交付物必须包含验收时看什么常见扣分点需求分析用例图、序列图、功能列表角色和用例是否覆盖登录、查询开课、查询选课、查询成绩、选课、退课只画登录选课和退课没有序列软件设计对象模型、用例图、序列图、至少一个重要对象状态图、主要界面学生、教师、课程、选课记录是否成为对象对象模型和数据库表完全对不上软件测试不同方法设计的测试数据至少 20 个不同对象测试序列正常、边界、异常是否都有20 条全是正确登录源代码手动编写的代码可忽略自动生成部分登录、选课、退课、成绩查询是否有实现只交界面文件没有业务逻辑书面报告目的、要求、内容、评价、心得章节完整图表编号清楚心得写成空话系统评价没有具体指标这张表不是让你照抄而是让你在动手前知道每一章最后要产出什么。需求分析阶段产出的用例图后面要能在软件设计里找到对应对象软件设计里的状态图后面要能在测试数据里找到状态迁移用例。指导书强调“整个系统的开发过程及方法应符合软件工程的要求”落到操作上就是图不是装饰图要能追到代码和测试。2.2 用例图、序列图、对象模型和状态图落到哪些文件用例图先定角色。选课系统里至少有三类角色学生、教师、系统管理员。学生侧用例包括登录、查询开课情况、查询选课情况、查询成绩、选课、退课教师侧用例包括登录、查询开课情况、录入或查询成绩管理员侧用例可以包括维护学生信息、维护教师信息、维护课程信息。指导书的功能要求写的是“至少应有登录、查询开课情况、查询选课情况、查询成绩、选课、退课等”所以用例图不要只画学生一侧教师和课程维护也要有落点。序列图不要画成“用户点击按钮系统返回结果”这种一句话图。登录序列图至少要有登录界面、登录控制对象、学生表访问对象、数据库选课序列图要有选课界面、选课控制对象、课程表访问对象、选课表访问对象、数据库并且把“检查人数限制、检查先行课、检查重复选课、写入选课记录、更新选课人数”几个消息按顺序画出来。退课序列图要把“删除选课记录、减少选课人数”画成事务里的两个动作。成绩查询序列图要体现按学号和课号过滤。对象模型用 Student、Teacher、Course、Enrollment 四个核心对象就够撑起选课系统。Student 有学号、姓名、密码、性别、出生年月、籍贯、地址、电话、家庭地址Teacher 有教师号、姓名、教研室、职称、性别、电话Course 有课号、课名、学分、先行课号、课时、开课教室、人数限制、选课人数Enrollment 有学号、课号、考试成绩、平时成绩、总评成绩。对象模型里的关联关系要和数据库表的主外键对应比如 Enrollment 关联 Student 和 CourseCourse 自关联到先行课号。状态图选“选课记录”最合适。状态可以定为未选、已选、已退、已录成绩。未选到已选需要人数未满、先行课满足、没有重复选课已选到已退需要退课操作已选到已录成绩需要教师录入成绩。状态图不用画得多复杂但每条迁移要有触发条件后面测试数据就能按这些迁移设计。主要界面至少包括登录界面、开课查询界面、选课界面、退课界面、成绩查询界面。界面截图放进报告时最好把控件命名也标一下比如登录按钮叫 btnLogin学号输入框叫 edtStudentId后面写代码和排查时能对上。2.3 测试数据与源代码提交边界指导书要求测试数据至少包括 20 个不同的对象测试序列并且要用不同方法设计测试数据。常见做法是等价类划分加边界值登录分正确学号正确密码、正确学号错误密码、不存在学号、空学号选课分正常选课、重复选课、人数已满、先行课未修、课号不存在退课分已选课程退课、未选课程退课、退课后再次退课成绩查询分有成绩、无成绩、成绩为 0、总评成绩边界 60。20 条不是凑数而是覆盖不同对象和不同状态迁移。源代码提交边界要写清楚只交手写代码自动生成的窗体文件可以省略。报告里可以贴关键代码段但不要把整个工程文件贴进去。指导书原文写“程序部分只须包含手动编写的代码可损略自动生成的部分”这里的“可损略”应是“可省略”的笔误。提交时建议保留工程文件、主窗体手写代码、数据库脚本和测试数据说明自动生成的备份文件不要打包进去。3. 数据模型与数据库搭建把一张大表拆成四张表指导书列出的字段很多学生姓名、学号、登录密码、性别、出生年月、籍贯、地址、学生电话、家庭地址、教师号、教师姓名、教研室、职称、性别、教师电话、课名、课号、学分、先行课号、课时、开课教室、人数限制、选课人数、考试成绩、平时成绩、总评成绩。新手最容易把这些字段全塞进一张表结果选课人数重复存储、教师信息重复录入、成绩和课程混在一起。合格做法是按对象拆成学生表、教师表、课程表、选课表四张核心表再按需要加管理员表。拆表的原则是一个对象一张表一个多对多关系一张中间表。学生和课程是多对多选课表就是中间表同时承载考试成绩、平时成绩、总评成绩。课程表里的“选课人数”是冗余字段用来快速判断人数限制但它必须和选课表的实际记录数对得上后面排查章节会给对账 SQL。3.1 字段规范化四张核心表怎么落下面这段 Access 2000 近似 DDL 可以在 Access 查询视图里执行字段长度按实际调整。表名用英文字段名用英文缩写界面显示中文这样后面 C Builder 里写 SQL 不容易碰到空格和保留字。-- 学生表学号做主键密码字段不要用 password 这类保留字 CREATE TABLE students ( student_id TEXT(20) NOT NULL PRIMARY KEY, student_name TEXT(30) NOT NULL, pwd TEXT(30) NOT NULL, gender TEXT(2), birth_date DATETIME, native_place TEXT(50), address TEXT(100), phone TEXT(20), home_address TEXT(100) ); -- 教师表教师号做主键 CREATE TABLE teachers ( teacher_id TEXT(20) NOT NULL PRIMARY KEY, teacher_name TEXT(30) NOT NULL, department TEXT(50), title TEXT(30), gender TEXT(2), phone TEXT(20) ); -- 课程表enrolled 是冗余人数capacity 是人数限制 CREATE TABLE courses ( course_id TEXT(20) NOT NULL PRIMARY KEY, course_name TEXT(50) NOT NULL, credits DOUBLE, pre_course_id TEXT(20), hours INTEGER, classroom TEXT(30), capacity INTEGER, enrolled INTEGER DEFAULT 0 ); -- 选课表一名学生选一门课只有一条记录 CREATE TABLE enrollments ( enroll_id COUNTER PRIMARY KEY, student_id TEXT(20) NOT NULL, course_id TEXT(20) NOT NULL, usual_score DOUBLE, exam_score DOUBLE, total_score DOUBLE );代码后的逻辑说明students 存学生基本信息和登录密码teachers 存教师信息courses 存课名、课号、学分、先行课号、课时、开课教室、人数限制和选课人数enrollments 存选课关系和三组成绩。参数说明TEXT(20) 表示短文本字段DOUBLE 表示双精度数值DATETIME 表示日期时间COUNTER 是 Access 的自增主键。Access 里外键关系可以在“关系”窗口里拖拽建立也可以在执行 DDL 后手动补关系如果 DDL 里的外键约束报错先建表再拖关系更稳。课程表里的 pre_course_id 是先行课号它指向 courses.course_id。选课检查时如果先行课号不为空就去 enrollments 里查该学生是否已经修过先行课并且总评成绩达到及格线。课程设计场景可以把及格线写成 60也可以写成常量后面二次开发再改成配置项。3.2 Access 建库与 ODBC 数据源配置先用 Access 建一个空的 .mdb 文件比如放在短英文路径C:\course_design\course.mdb再执行上面的建表语句。数据可以手工录入几条学生、教师、课程记录方便调试。数据库路径不要放桌面不要带中文和空格旧工具在路径解析上容易出玄学问题。ODBC 数据源按下面顺序配置前后步骤要连着做不要中途换管理器打开 32 位 ODBC 数据源管理器。C Builder 6.0 是 32 位工具必须用 32 位管理器建数据源。选择“用户 DSN”或“系统 DSN”点击“添加”。驱动选择 Access 驱动*.mdb不要选成其他数据库驱动。数据源名填“选课数据源”描述可以留空。在数据库选择里定位到C:\course_design\course.mdb点击确定。回到数据源列表确认“选课数据源”已经出现点击确定保存。提示如果 64 位系统里只看到 64 位 ODBC 管理器建出来的数据源在 C Builder 6.0 里可能找不到必须找 32 位管理器。指导书附录还提到 BDE Administrator 的建别名流程打开 BDE Administrator新建 Database Driver Name选择 Access 驱动设置 ODBC 数据源Apply 后 Open 测试字体变黑表示连接成功。实际做课程设计时BDE 和 ADO 不必双套都上。C Builder 6.0 里用 ADOConnection 直接连 ODBC 数据源更直观BDE 可以作为备用路径。常见做法是ODBC 建数据源ADOConnection 的 ConnectionString 指向该数据源ADOQuery 挂在 ADOConnection 上。3.3 连接串与 BDE/ADO 的落点ADOConnection 的 ConnectionString 可以写成下面这样DSN 写 ODBC 数据源名DBQ 写数据库绝对路径UID 和 PWD 留空表示 Access 无密码。DSN选课数据源; DBQC:\course_design\course.mdb; UID; PWD;参数说明DSN 是 ODBC 数据源名必须和 ODBC 管理器里建的名字完全一致DBQ 是数据库文件路径路径里有空格时要用引号包住UID 和 PWD 是数据库用户名密码Access 单机库通常为空。连接串写完后点“测试连接”测试成功再挂 ADOQuery。ADOQuery 的 Connection 属性指向 ADOConnectionSQL 语句里用:参数名占位不要用字符串拼接。如果走 BDE别名里的 PATH 指向数据库所在目录DATABASE NAME 指向 .mdb 文件。BDE 的坑在于别名和 ODBC 数据源是两套配置改了一边没改另一边就会连不上。我一般会让学生统一走 ADOBDE 只作为指导书附录里的了解内容避免两套配置互相打架。4. 核心功能链路登录、查课、选退课、成绩查询怎么串起来选课系统的功能要求看起来不多登录、查询开课情况、查询选课情况、查询成绩、选课、退课。真正写起来难点在业务顺序和事务边界。登录要先查学生表选课要先查课程容量和先行课退课要同时删选课记录和减人数成绩查询要按学号和课号过滤。界面控件可以拖SQL 和事务不能乱。我一般会把主窗体分成几个页签或几个子窗体登录、开课查询、选课、退课、成绩查询。控件命名统一用前缀edt 表示输入框btn 表示按钮qry 表示 ADOQueryds 表示 DataSourcedbg 表示 DBGrid。这样后面看代码时edtStudentId 和 qryCourse 一眼能认出来。4.1 登录与会话状态登录不要用字符串拼接 SQL学号里带单引号就会翻车。用参数化查询把学号和密码作为参数传进去。下面这段 C Builder 6.0 风格的代码可以放在登录按钮事件里。// 登录参数化查询返回学生姓名失败返回空串 AnsiString TryLogin(AnsiString sid, AnsiString pwd) { qryLogin-Close(); qryLogin-SQL-Clear(); qryLogin-SQL-Add(SELECT student_id, student_name FROM students WHERE student_id:sid AND pwd:pwd); qryLogin-Parameters-ParamByName(sid)-Value Trim(sid); qryLogin-Parameters-ParamByName(pwd)-Value Trim(pwd); qryLogin-Open(); if (qryLogin-Eof) { return ; // 登录失败 } return qryLogin-FieldByName(student_name)-AsString; }逻辑说明先关闭上一次查询清空 SQL再重新加语句ParamByName(sid)和ParamByName(pwd)分别绑定学号和密码Open()执行查询Eof为真表示没有匹配记录。参数说明sid 是学号输入框的值pwd 是密码输入框的值Trim 用来去掉首尾空格。登录成功后把学生学号存到全局变量或主窗体成员变量里后面选课、退课、查成绩都用这个学号不要每次让用户重新输入。登录失败要给出明确提示比如“学号或密码不正确”不要只弹一个空框。连续失败三次可以锁定一分钟课程设计里不强制但加上去报告里好写。教师登录可以另做一个入口查教师表成功后记住教师号成绩录入时用。4.2 选课与退课事务选课的业务顺序是检查课程是否存在、检查人数是否已满、检查先行课是否满足、检查是否重复选课、写入选课记录、更新课程选课人数。写入选课记录和更新人数必须在一个事务里否则会出现选课表有记录但人数没加或者人数加了但选课记录没写进去。// 选课返回 true 表示成功msg 带回失败原因 bool EnrollCourse(AnsiString sid, AnsiString cid, AnsiString msg) { // 1. 查课程容量和先行课 qryCourse-Close(); qryCourse-SQL-Clear(); qryCourse-SQL-Add(SELECT capacity, enrolled, pre_course_id FROM courses WHERE course_id:cid); qryCourse-Parameters-ParamByName(cid)-Value cid; qryCourse-Open(); if (qryCourse-Eof) { msg 课号不存在; return false; } int capacity qryCourse-FieldByName(capacity)-AsInteger; int enrolled qryCourse-FieldByName(enrolled)-AsInteger; AnsiString preId qryCourse-FieldByName(pre_course_id)-AsString; if (enrolled capacity) { msg 人数已满; return false; } // 2. 检查先行课示例只判断是否修过且总评及格 if (!preId.IsEmpty()) { qryPre-Close(); qryPre-SQL-Clear(); qryPre-SQL-Add(SELECT total_score FROM enrollments WHERE student_id:sid AND course_id:preid); qryPre-Parameters-ParamByName(sid)-Value sid; qryPre-Parameters-ParamByName(preid)-Value preId; qryPre-Open(); if (qryPre-Eof || qryPre-FieldByName(total_score)-AsFloat 60) { msg 先行课未通过; return false; } } // 3. 检查重复选课 qryDup-Close(); qryDup-SQL-Clear(); qryDup-SQL-Add(SELECT COUNT(*) AS cnt FROM enrollments WHERE student_id:sid AND course_id:cid); qryDup-Parameters-ParamByName(sid)-Value sid; qryDup-Parameters-ParamByName(cid)-Value cid; qryDup-Open(); if (qryDup-FieldByName(cnt)-AsInteger 0) { msg 不能重复选课; return false; } // 4. 事务写入先插选课记录再按容量条件更新人数 try { adoConn-BeginTrans(); qryIns-Close(); qryIns-SQL-Clear(); qryIns-SQL-Add(INSERT INTO enrollments(student_id, course_id) VALUES(:sid, :cid)); qryIns-Parameters-ParamByName(sid)-Value sid; qryIns-Parameters-ParamByName(cid)-Value cid; qryIns-ExecSQL(); qryUpd-Close(); qryUpd-SQL-Clear(); qryUpd-SQL-Add(UPDATE courses SET enrolledenrolled1 WHERE course_id:cid AND enrolledcapacity); qryUpd-Parameters-ParamByName(cid)-Value cid; int affected qryUpd-ExecSQL(); if (affected ! 1) { throw Exception(人数已满更新失败); } adoConn-CommitTrans(); msg 选课成功; return true; } catch (Exception e) { adoConn-RollbackTrans(); msg e.Message; return false; } }逻辑说明前半段是检查后半段是事务写入。BeginTrans开启事务CommitTrans提交RollbackTrans回滚。ExecSQL返回受影响行数更新人数时用WHERE enrolledcapacity再判一次容量防止并发下超选。参数说明sid 是当前登录学生学号cid 是课程号msg 是返回给界面的提示。异常捕获里要回滚不然事务挂住会影响后续操作。退课事务反过来先查选课记录是否存在再删记录再减人数。减人数时用UPDATE courses SET enrolledenrolled-1 WHERE course_id:cid AND enrolled0防止人数变成负数。退课和选课都要刷新 DBGrid让用户马上看到结果。4.3 成绩查询与界面绑定成绩查询按学号过滤可选按课号过滤。SQL 用 JOIN 把课程名带出来界面上显示课号、课名、学分、平时成绩、考试成绩、总评成绩。// 成绩查询按当前学生学号查课号为空表示全部 void LoadScores(AnsiString sid, AnsiString cid) { qryScore-Close(); qryScore-SQL-Clear(); AnsiString sql SELECT c.course_id, c.course_name, c.credits, e.usual_score, e.exam_score, e.total_score FROM enrollments e INNER JOIN courses c ON e.course_idc.course_id WHERE e.student_id:sid; if (!cid.IsEmpty()) { sql AND e.course_id:cid; } qryScore-SQL-Add(sql); qryScore-Parameters-ParamByName(sid)-Value sid; if (!cid.IsEmpty()) { qryScore-Parameters-ParamByName(cid)-Value cid; } qryScore-Open(); dsScore-DataSet qryScore; dbgScore-DataSource dsScore; }逻辑说明SQL 用 INNER JOIN 把选课表和课程表连起来课号不为空时追加条件。参数说明sid 是当前学生学号cid 是可选课号。界面绑定用 DataSource 和 DBGriddsScore-DataSet qryScore把数据集挂到数据源dbgScore-DataSource dsScore把数据源挂到表格。查询后不要忘记Open()否则 DBGrid 是空的。开课查询和选课查询可以共用课程查询数据集开课查询看课程表全量选课查询看当前学生已选课程。序列图上对应的消息就是界面触发查询、控制对象拼 SQL、数据集打开、表格刷新。测试时先录一条学生、一门课、一条选课记录再逐项验证。5. 常见问题排查ODBC、ADO、Access 和旧工具的五个坑旧工具链的坑很集中ODBC 位数不对、路径带空格、参数绑定错位、事务没包住、数据库引擎缺失。下面五条是课程设计里最容易翻车的记录每条按“现象、原因、解决”写照着排查能省不少时间。5.1 环境与连接排查现象一ODBC 管理器里明明建了“选课数据源”ADOConnection 测试连接却报“找不到数据源名称”。原因通常是位数不匹配C Builder 6.0 是 32 位程序读的是 32 位 ODBC 数据源而你在 64 位管理器里建的数据源它看不到。解决方法是打开 32 位 ODBC 数据源管理器重新建一遍建完在 ADOConnection 的 ConnectionString 里把 DSN 写成完全一致的名字注意不要多空格。血泪经验是数据源名里不要带中文括号界面显示正常连接串解析时容易出问题。现象二数据库文件放在桌面或中文目录测试连接时报“找不到文件”或“无效路径”。原因是旧版 Access 驱动对长路径、空格、中文路径的解析不稳定路径里有空格时 DBQ 没加引号也会断。解决方法是把 .mdb 放到短英文路径比如C:\course_design\course.mdbDBQ 用绝对路径路径有空格时用双引号包住。建库后先复制一份备份改表结构前备份后悔药比排查快。现象三编译能过运行到qryLogin-Open()就报“未指定的错误”。原因可能是 ADOConnection 没连上、ADOQuery 的 Connection 属性没指向 ADOConnection或者数据源被别的程序占用。解决方法是先单独放一个按钮测试adoConn-Connected再看 ADOQuery 的 Connection 属性Access 数据库被打开时可能锁住调试时关掉 Access 界面。旧工具没有黑匣子错误信息很短只能按连接、数据集、SQL 三段拆。5.2 数据一致性与业务排查现象四选课成功提示出来了但课程表里的选课人数没变或者人数加了但选课表没有记录。原因是插入和更新没放在同一个事务里或者更新语句没有判断受影响行数。解决方法是把BeginTrans、插入、更新、CommitTrans包在 try 块里异常时RollbackTrans更新人数时用WHERE enrolledcapacity并检查ExecSQL()返回值是否为 1。下面这段对账 SQL 可以定期跑找出人数和实际记录不一致的课程。-- 对账课程表 enrolled 与选课表实际记录数不一致的课程 SELECT c.course_id, c.course_name, c.enrolled AS stored_count, COUNT(e.student_id) AS real_count FROM courses c LEFT JOIN enrollments e ON c.course_id e.course_id GROUP BY c.course_id, c.course_name, c.enrolled HAVING c.enrolled COUNT(e.student_id);逻辑说明LEFT JOIN 保证没有选课记录的课程也能查出来COUNT(e.student_id) 统计实际选课人数HAVING 过滤出不一致的行。参数说明stored_count 是课程表冗余人数real_count 是选课表实际人数。查出来之后不要手工乱改先看是插入失败还是更新失败再决定补记录还是重算人数。现象五换一台机器演示时程序打不开数据库提示驱动不存在。原因是目标机器没装对应版本的 Access 数据库引擎或者装的是 64 位引擎而程序是 32 位。解决方法是提前在演示机器上装 32 位 Access 驱动或者把运行环境做成虚拟机镜像提交前在干净环境里跑一遍登录、选课、退课、查成绩四条链路。课程设计答辩现场最怕“在我电脑上是好的”所以打包时把数据库、驱动说明、数据源配置步骤写进 README别只交一个 exe。6. 二次开发把课程设计从能跑改成能讲清楚课程设计做完基础功能后二次开发不用贪多挑三个点就能让答辩时有的讲角色权限、选课时间窗口、成绩录入校验。角色权限在登录后区分学生和教师学生只能选退课和查自己的成绩教师只能录成绩和查开课改动位置在登录成功后的主窗体初始化验证方法是分别用学生账号和教师账号登录看菜单项是否灰掉。选课时间窗口在课程表加 start_time 和 end_time 两个字段选课前判断当前时间是否在窗口内验证方法是把窗口设成过去时间看选课按钮是否提示“不在选课时间”。成绩录入校验在保存总评成绩时判断平时成绩和考试成绩是否在 0 到 100 之间总评按比例算完后回写验证方法是输入 -1 和 101看是否拦截。改造点改动位置验证方法角色权限登录事件、主窗体菜单初始化学生账号看不到成绩录入教师账号看不到选课选课时间窗口courses 表加时间字段EnrollCourse 开头判断窗口外选课提示失败窗口内成功成绩录入校验成绩保存按钮事件输入 -1、101、正常值三组数据看提示人数对账管理员菜单加对账按钮执行对账 SQL手工改错 enrolled 后能查出不一致对账 SQL 可以直接用上一章那段查到不一致后提供“按选课表重算人数”的按钮执行UPDATE courses SET enrolled(SELECT COUNT(*) FROM enrollments WHERE enrollments.course_idcourses.course_id)。这样答辩时老师问“选课人数错了怎么办”你有排查路径也有修复动作。从那以后我每次带课程设计都先让学生跑一遍人数对账 SQL再谈界面美化这份指导书里的操作指南和报告模板适合拿来当底盘改完记得在干净环境里重跑登录、选课、退课、查成绩四条链路。希望帮到你。本文还有配套的精品资源点击获取

相关推荐

SpringBoot整合Druid连接Oracle超时问题解决方案
SpringBoot整合Druid连接Oracle超时问题解决方案

1. 问题背景与现象描述 最近在基于SpringBoot的项目中整合dynamic-datasource和Druid连接池连接Oracle数据库时,遇到了一个棘手的问题:尽管在Druid配置中明确设置了oracle.net.CONNECT_TIMEOUT参数,但在实际连接超时场景下该配置并未生效。这… · 2026/11/3 11:16:54

5G与数据中心驱动下的光纤预制棒技术与市场分析
5G与数据中心驱动下的光纤预制棒技术与市场分析

1. 光纤预制棒行业概览:5G与数据中心双轮驱动的隐形冠军 光纤预制棒这个听起来有些陌生的工业产品,实际上是整个光通信产业链的"芯片级"核心材料。作为制造光纤的原始坯体,它的质量直接决定了最终光纤的传输性能。如果把光纤比作信… · 2026/11/3 11:16:54

OpenClaw端口修改与配置优化实战指南
OpenClaw端口修改与配置优化实战指南

1. OpenClaw端口修改的必要性与场景分析 OpenClaw作为一款流行的跨平台工具,默认使用18789端口进行通信。但在实际部署中,这个端口可能面临三类典型问题: 端口冲突 :当服务器上已有服务占用18789时(常见于企业环境&a… · 2026/11/3 11:16:54

HDMI TMDS信号完整性调试:波形捕获与眼图分析实战指南
HDMI TMDS信号完整性调试:波形捕获与眼图分析实战指南

HDMI接口从消费电子一路铺到工控、医疗显示和车载娱乐,几乎成了高清视频传输的默认选项。但真正在硬件调试一线待过的人都知道,HDMI链路出问题的概率远比想象中高——花屏、闪屏、偶发黑屏、热插拔后不识别,这些现象背后十有八九都指向同一个… · 2026/11/3 15:12:40

WeGame多账号自动登录工具开发实战
WeGame多账号自动登录工具开发实战

1. 项目背景与需求解析在游戏多开、账号托管等场景中,手动逐个登录WeGame账号效率极低。特别是工作室或代练团队需要同时管理数十个游戏账号时,传统登录方式耗时耗力。远程自动登录工具正是为解决这一痛点而生——通过模拟人工操作实现批量账号导入、自动… · 2026/11/3 15:12:40

TensorFlow安装避坑指南:从环境配置到GPU加速实战
TensorFlow安装避坑指南:从环境配置到GPU加速实战

上周有个读者私信问我:“哥,我刚装完TensorFlow,import都能成功,可一跑训练就提示找不到cudnn64_8.dll,整个人都懵了。”我一看就知道,他八成是在Windows上直接pip install了最新版TensorFlow,然… · 2026/11/3 15:12:40

hindsight 智能体记忆系统:从记忆回溯到 MCP 与 Docker 工程实践
hindsight 智能体记忆系统:从记忆回溯到 MCP 与 Docker 工程实践

1. 从“hindsight”这个词说起:为什么它值得单独拿出来聊第一次看到“hindsight”作为项目标题,我脑子里蹦出来的不是某个具体工具,而是一个很朴素的场景:你让一个智能体帮你处理一件跨天、跨会话的任务,它当时做得挺好… · 2026/11/3 15:12:40

Pattern与Mattern:字符串模式匹配的编译与执行分离设计
Pattern与Mattern:字符串模式匹配的编译与执行分离设计

1. 从两个函数名说起:Pattern 与 Mattern 到底在解决什么问题第一次看到Pattern()和Mattern()这两个名字摆在一起,我下意识以为是谁把Pattern拼错了,写成了Mattern。后来翻了一圈代码库才发现,这俩函数经常成对出现在字符串匹配、… · 2026/11/3 15:12:40

图计算工程化实践:让AI应用从能跑到能维护
图计算工程化实践:让AI应用从能跑到能维护

1. 从"能跑就行"到"能维护才行":图计算应用开发的真实分水岭做过几个AI应用之后你会发现一个挺尴尬的事实:Demo阶段跑得飞起的东西,一旦要交给别人维护、要加新功能、要排查线上问题,立刻就变成一团乱麻。模型… · 2026/11/3 15:11:34

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 6:04:24

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 5:52:46

STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战
STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59

ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题
ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59

基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践
基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 6:04:24

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 5:52:46

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码