ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

健康档案管理系统数据库课程设计:从ER建模到MySQL优化避坑全指南

健康档案管理系统数据库课程设计:从ER建模到MySQL优化避坑全指南 简介数据库课程设计——健康档案管理系统.doc 是一份完整的数据库课程设计文档面向计算机相关专业学生、正在完成数据库原理课程设计或需要参考健康档案管理系统设计方案的开发者。文档覆盖课程设计的目的与意义、需求分析、数据流图与数据字典、概要结构设计、逻辑结构设计、物理结构设计等环节系统以病历文件和体检文件为核心实现登记、修改、删除、查询、统计五大功能统计部分包括一般统计与动态分析可完成计数、平均值、年增长值和增长率等分析。文档还定义了原始数据、反馈信息、统计信息、查询信息、报表等多个数据流条目字段涵盖学号、姓名、性别、系别、年龄、身高、体重、胸围、日期、诊断、医疗记录等层次完整。资源包内仅含1个doc文件文件大小876KB结构清晰、便于直接参考和修改使用。这份文档已有341人学习使用适合作为数据库课程设计报告模板和健康档案管理系统的分析与设计参考。1. 健康档案管理系统一个数据库课程设计题目为什么值得认真做《数据库课程设计——健康档案管理系统》是数据库课设题目里出镜率极高的一个。很多人拿到这个题第一反应是找个模板改改登录页加四个菜单、几张表增删改查、截图粘贴进Word文档然后交差。但真正拉开分数差距的不是页面有多好看而是数据库本身ER模型规不规范、有没有冗余和NULL设计缺陷、索引是否让查询走对路径、视图和存储过程到底是在干活还是在表演。这里按我带人和自己做过几轮课设的思路从需求建模讲到建表、索引、视图、存储过程再落到排错和答辩演示适合正在用MySQL做课设或者想把它扩展成毕设底子的读者。2. 需求与ER建模四个模块对应五张核心表在打开数据库客户端之前先把需求圈定。健康档案管理系统的核心数据是“居民健康档案”但它不是一张大表能装下的。常规拆法是四个模块居民档案管理、体检记录管理、门诊就诊记录管理、慢性病随访管理外加一个登录与角色权限。很多同学把科室名字直接写在就诊记录里后期科室改名就得UPDATE几百行这就是没做基础数据表设计的代价。2.1 功能边界先定死居民档案、体检、门诊、随访四个模块典型功能清单大致是管理员维护居民信息医生录入体检和门诊结果居民本人查询自己的历史记录。边界不卡死很容易越做越大。有人会把预约挂号、药品库存也塞进来最后变成半个医院信息系统ER图二十张表起步课设周期根本扛不住。我一般只保留四个模块。居民档案建档、改档、按身份证或姓名模糊查询。体检记录新增身高、体重、血压、血糖等指标查看历史列表和最近一次体检。门诊记录记录就诊时间、科室、主诉、诊断和用药。慢病随访针对高血压、糖尿病等做周期性随访记录随访日期和关键指标。角色权限在课程阶段用一张user表加role字段足够不需要上Spring Security或Shiro那一套。数据库设计有没有考虑角色是设计说明书里能写、答辩时能讲清楚的东西。把模块数量控制在四个既覆盖了健康档案的主流业务又不会让建表工作量失控。2.2 实体梳理与关系ER模型里最容易画错的医生实体基础实体包括用户、居民档案、体检记录、门诊记录、慢病随访。关系上一个居民可以有多条体检记录、多条门诊记录、多条随访记录所以都是1对N。那有没有M对N关系要不要独立关联表在完整业务模型里“居民—医生”是多对多但课程设计阶段没必要把医生独立成表因为医生只出现在体检记录和门诊记录两个事实表里作为姓名字段存储即可。如果硬把医生抽成实体就得在两张事实表里各加doctor_id外键设计没错但演示时多一张空表反而不好看。实体主键关键属性与居民档案关系sys_useruser_id登录名、密码散列、角色1:1patient_profileprofile_id身份证号、血型、过敏史建档主体physical_examexam_id身高、体重、血压、血糖N:1visit_recordvisit_id科室、主诉、诊断、处方N:1chronic_followupfollowup_id病种、随访日期、指标N:1这里有个反例值得说很多人把体检医生放在体检记录表又单独建一张医生表存放科室两处的医生信息没有外键关联E-R图前后矛盾。如果课程设计对E-R图要求完整可以统一抽一张医务人员表两个事实表都引用它的staff_id如果只求系统能跑名字字段先顶着但E-R图上要能自圆其说。2.3 规范化到第三范式一个反例说明为什么要拆表病历场景里最典型的违反第一范式写法是把一次体检的多个指标拼在一个“结果”字段里例如“身高175体重70血压120/80血糖5.6”存成一段字符串。想按血压范围筛选居民时SQL根本写不出来。第二范式主要针对联合主键的局部依赖用自增单列主键后基本绕开。第三范式的坑更常见在体检记录表里冗余“居民姓名”。姓名属于档案表体检记录只该存profile_id。冗余之后居民改名时得同时改档案表和所有体检记录漏一条数据就打架。拆表的标准动作是先按实体画E-R图再逐个确认属性是否只依赖该表主键。我把体检记录拆成physical_exam一张表里面不出现姓名、身份证号查询时JOIN档案表取姓名。另一个容易纠结的点是主键选择身份证号业务上唯一但长度18位作为主键会让二级索引变大而且它是敏感信息更稳的做法是用自增profile_id做逻辑主键身份证号单独建UNIQUE约束。这样设计初期多花十分钟后面所有查询都少踩坑。3. 用MySQL落库健康档案表DDL、约束与索引ER模型确认后进入建库建表环节。下面的脚本默认在MySQL 8.0本地实例上跑通字符集用utf8mb4。学校机房如果是5.7窗口函数和部分语法支持有差异我会在相应位置标注。3.1 建库与字符集MySQL 里 utf8mb4 比 utf8 多什么很多课设模板建库时写utf8中文一多就翻车。MySQL里的utf8是utf8mb3的别名最多3字节存不了emoji和部分生僻字utf8mb4才是完整的UTF-8实现4字节。健康档案里居民姓名、地址、过敏史都可能出现生僻字统一定义utf8mb4最保险。CREATE DATABASE health_record DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;逻辑说明character set决定字符怎么编码collation决定排序和比较规则。utf8mb4_general_ci后缀_ci表示大小写不敏感适合姓名和地址的模糊查询如果希望用户名严格区分大小写collation可以改utf8mb4_bin。这里用general_ci已经满足课设不必追新版MySQL的utf8mb4_0900_ai_ci。参数说明建库后记得执行SHOW CREATE DATABASE health_record;检查字符集同时保证客户端连接也声明了同样的字符集。命令行下执行SET NAMES utf8mb4;JDBC连接串加useUnicodetruecharacterEncodingutf8。这四个地方任何一处漏掉后面写中文就可能变成问号而且问题出在连接层建表语句里看不出毛病。3.2 五张核心表的DDL字段、主外键与约束一次写对建表顺序有讲究先建sys_user再建patient_profile最后建依赖档案表的physical_exam、visit_record、chronic_followup。下面给出完整脚本突出外键、注释和合理的字段类型。CREATE TABLE sys_user ( user_id INT AUTO_INCREMENT PRIMARY KEY COMMENT 用户ID, username VARCHAR(50) NOT NULL UNIQUE COMMENT 登录名, password_hash CHAR(64) NOT NULL COMMENT 密码SHA-256散列不存明文, real_name VARCHAR(50) NOT NULL COMMENT 真实姓名, role TINYINT NOT NULL DEFAULT 2 COMMENT 0:管理员 1:医生 2:居民, phone VARCHAR(20) NULL COMMENT 联系电话, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT系统用户表;CREATE TABLE patient_profile ( profile_id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL, id_card VARCHAR(18) NOT NULL UNIQUE COMMENT 身份证号, gender ENUM(M,F) NOT NULL COMMENT M男 F女, birth_date DATE NOT NULL, blood_type ENUM(A,B,AB,O,UNKNOWN) DEFAULT UNKNOWN, allergy_history VARCHAR(500) NULL COMMENT 过敏史, emergency_contact VARCHAR(50) NULL, emergency_phone VARCHAR(20) NULL, address VARCHAR(200) NULL, last_exam_date DATE NULL COMMENT 最近体检日期由存储过程维护, last_bmi DECIMAL(4,2) NULL COMMENT 最近BMI值, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, CONSTRAINT fk_profile_user FOREIGN KEY (user_id) REFERENCES sys_user(user_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT居民健康档案表;CREATE TABLE physical_exam ( exam_id INT AUTO_INCREMENT PRIMARY KEY, profile_id INT NOT NULL, exam_date DATE NOT NULL, height DECIMAL(5,2) COMMENT 身高cm, weight DECIMAL(5,2) COMMENT 体重kg, systolic SMALLINT COMMENT 收缩压mmHg, diastolic SMALLINT COMMENT 舒张压mmHg, heart_rate SMALLINT COMMENT 心率 次/分, fasting_glucose DECIMAL(4,1) COMMENT 空腹血糖 mmol/L, bmi DECIMAL(4,2) COMMENT BMI由触发器计算, conclusion VARCHAR(200) COMMENT 体检结论, examiner VARCHAR(50) COMMENT 体检医生姓名, CONSTRAINT fk_exam_profile FOREIGN KEY (profile_id) REFERENCES patient_profile(profile_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT体检记录表;CREATE TABLE visit_record ( visit_id INT AUTO_INCREMENT PRIMARY KEY, profile_id INT NOT NULL, visit_date DATETIME NOT NULL COMMENT 就诊时间, department VARCHAR(50) COMMENT 科室, doctor VARCHAR(50) COMMENT 接诊医生, chief_complaint VARCHAR(500) COMMENT 主诉, diagnosis VARCHAR(500) COMMENT 诊断, prescription VARCHAR(500) COMMENT 处方/用药, CONSTRAINT fk_visit_profile FOREIGN KEY (profile_id) REFERENCES patient_profile(profile_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT门诊就诊记录表;CREATE TABLE chronic_followup ( followup_id INT AUTO_INCREMENT PRIMARY KEY, profile_id INT NOT NULL, disease_type VARCHAR(20) NOT NULL COMMENT 高血压/糖尿病, followup_date DATE NOT NULL, systolic SMALLINT NULL, diastolic SMALLINT NULL, fasting_glucose DECIMAL(4,1) NULL, medication VARCHAR(200) COMMENT 当前用药情况, doctor_advice VARCHAR(200) COMMENT 指导意见, CONSTRAINT fk_followup_profile FOREIGN KEY (profile_id) REFERENCES patient_profile(profile_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT慢性病随访记录表;逻辑说明这五个脚本合起来就是一张建库交接单。ENGINEInnoDB是外键约束生效的前提InnoDB才支持事务和外键。password_hash用CHAR(64)固定存SHA-256散列结果明文密码一律不允许入库。DECIMAL(5,2)表示最多5位数字、其中2位小数身高体重足够血糖DECIMAL(4,1)留一位小数。血压用SMALLINT而不是TINYINT因为收缩压理论上能过200TINYINT上限只有127。参数说明varchar长度不要照抄根据演示数据的实际长度调整短了会报Data too long。身份证号合法性和18位校验可以在应用层做数据库里靠UNIQUE约束兜底防重复。MySQL 8.0.16以下的CHECK约束语法不检查所以不必在表里写CHECK。3.3 索引设计不是每个列都建也不是不建常见错误把gender、blood_type也建索引觉得“每个where都能加速”但枚举值可区分度太低索引扫描可能比全表扫还慢。另一类问题外键列不建索引。InnoDB对外键列即使不显式建索引也常会自动生成辅助索引但为了语义清晰我建议显式声明。ALTER TABLE physical_exam ADD INDEX idx_exam_profile_date (profile_id, exam_date); ALTER TABLE visit_record ADD INDEX idx_visit_profile_date (profile_id, visit_date); ALTER TABLE chronic_followup ADD INDEX idx_followup_profile_date (profile_id, followup_date); ALTER TABLE patient_profile ADD INDEX idx_profile_birth (birth_date);逻辑说明idx_exam_profile_date是联合索引字段顺序(profile_id, exam_date)与查询模式“按某个居民查体检记录并按日期排序”匹配。单独按exam_date查而不过滤profile_id时这个联合索引用不上这符合最左前缀原则所以别把exam_date放第一位。参数说明索引不是越多越好每张事实表两到三个为宜。先写业务查询语句再看哪些列频繁出现在WHERE和ORDER BY里最后决定加索引。课设数据量小低基数列不要建索引只增加写入开销。写完DDL后执行SHOW CREATE TABLE physical_exam;核对外键和索引。4. 视图、存储过程与触发器让健康档案系统从“会存数据”升级为“会算数据”很多课设作品把数据库当存数据的盒子SQL只会INSERT和SELECT答辩老师一句“数据库对象你会哪些”就能问住。视图、存储过程、触发器是课程设计里最容易拿到加分的三个对象前提是它们真的承担了业务逻辑而不是为了存在而存在。4.1 视图v_latest_exam用窗口函数拿“每人最新体检记录”健康档案最常见的查询是“查看某个居民最近一次体检结果”。如果直接SELECT JOIN再ORDER BY exam_date拿到的是历史列表还得在代码里取第一条用视图把“每人最新一条”封装掉应用层只写SELECT * FROM v_latest_exam WHERE profile_id ?即可。CREATE OR REPLACE VIEW v_latest_exam AS WITH ranked AS ( SELECT e.*, ROW_NUMBER() OVER ( PARTITION BY e.profile_id ORDER BY e.exam_date DESC, e.exam_id DESC ) AS rn FROM physical_exam e ) SELECT profile_id, exam_date, height, weight, bmi, systolic, diastolic, heart_rate, fasting_glucose, conclusion FROM ranked WHERE rn 1;逻辑说明ROW_NUMBER() OVER是窗口函数PARTITION BY profile_id把同一个居民的多条体检记录分在一组ORDER BY exam_date DESC, exam_id DESC确保同一天多次体检时取最新一条外层WHERE rn 1每组只剩一条。这个写法在MySQL 8.0上能直接跑若机房是5.7老办法是自连接或GROUP BY取MAX(id)可读性差很多。参数说明视图本身不占存储每次查询都会执行内部SQL。数据量五万行以内的课设演示没问题如果造数据到百万行视图查询速度就会暴露第3章联合索引的价值。建议在视图里只暴露需要的列不要把密码散列这类敏感字段带出去。4.2 存储过程sp_insert_exam把“体检登记”做成一个事务体检登记不只是INSERT一条记录还要同步更新档案表里的last_exam_date和last_bmi。两步必须是一个事务INSERT成功而UPDATE失败数据就不一致。存储过程把整个流程包在一个事务里调用方只传原始参数。DELIMITER $$ CREATE PROCEDURE sp_insert_exam( IN p_profile_id INT, IN p_exam_date DATE, IN p_height DECIMAL(5,2), IN p_weight DECIMAL(5,2), IN p_systolic SMALLINT, IN p_diastolic SMALLINT, IN p_heart_rate SMALLINT, IN p_fasting_glucose DECIMAL(4,1), IN p_conclusion VARCHAR(200), IN p_examiner VARCHAR(50) ) BEGIN DECLARE v_bmi DECIMAL(4,2); DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN ROLLBACK; SIGNAL SQLSTATE 45000 SET MESSAGE_TEXT 体检数据写入失败事务已回滚; END; START TRANSACTION; SET v_bmi ROUND(p_weight / POWER(p_height / 100, 2), 2); INSERT INTO physical_exam (profile_id, exam_date, height, weight, bmi, systolic, diastolic, heart_rate, fasting_glucose, conclusion, examiner) VALUES (p_profile_id, p_exam_date, p_height, p_weight, v_bmi, p_systolic, p_diastolic, p_heart_rate, p_fasting_glucose, p_conclusion, p_examiner); UPDATE patient_profile SET last_exam_date p_exam_date, last_bmi v_bmi WHERE profile_id p_profile_id; COMMIT; END$$ DELIMITER ;逻辑说明DECLARE ... EXIT HANDLER FOR SQLEXCEPTION声明异常处理事务中任何SQL报错就ROLLBACK并用SIGNAL把错误信息抛给调用方。START TRANSACTION和COMMIT包住INSERT和UPDATE保证原子性。BMI由存储过程统一计算避免前端手算和数据库计算结果不一致。参数说明调用示例是CALL sp_insert_exam(1, 2025-06-10, 175.5, 70.2, 118, 76, 72, 5.4, 正常, 张医生);。身高单位cmPOWER(p_height/100, 2)先把cm转米再平方。ROUND控制BMI两位小数。如果表中还有计算BMI的触发器触发器要把“BMI已有值直接保留”的逻辑写上避免双重覆盖。4.3 触发器trg_bmi_calc算BMI这种派生列该不该落库BMI由身高体重实时算出严格说是派生数据。要不要落库看查询模式如果页面经常按BMI区间筛选居民视图临时算每次都要算全表落库成字段配合索引能快速查“超重人群”。课程设计里落库没错关键是同步机制不要靠应用层自觉用触发器兜底。DROP TRIGGER IF EXISTS trg_bmi_before_insert; DELIMITER $$ CREATE TRIGGER trg_bmi_before_insert BEFORE INSERT ON physical_exam FOR EACH ROW BEGIN IF NEW.bmi IS NULL OR NEW.bmi 0 THEN SET NEW.bmi ROUND(NEW.weight / POWER(NEW.height / 100, 2), 2); END IF; END$$ DELIMITER ;逻辑说明这是BEFORE INSERT触发器行写入前执行。NEW指即将插入的记录IF判断保证应用层或存储过程已传入有效BMI时不被覆盖。存储过程传入时触发器看到非NULL就跳过两层逻辑各司其职。参数说明触发器可以写跨表UPDATE比如同步档案表的last_bmi但跨表修改会让排查难度上升批量导入时还可能互相触发。更稳的做法是触发器只负责当前行的派生列计算跨表一致性交给存储过程的事务统一维护。在健康档案系统里触发器用来算BMI存储过程用来同步档案表边界清晰答辩也好解释。5. 健康档案系统高频避坑清单提交前必查的5个细节这一部分一半是我自己做课设时踩过的一半是帮别人排查时看到的。每条按现象、原因、解决展开建议提交前逐条过一遍。5.1 外键约束不生效删除主表记录后子表还在现象把patient_profile里一条记录DELETE掉以为physical_exam里对应记录会被级联删除结果子表数据原封不动页面上出现“查无档案的体检记录”。原因建表用了MyISAM引擎或外键约束语法写错。MySQL里只有InnoDB支持外键MyISAM会静默忽略FOREIGN KEY建表不报错但约束是假的。解决建表语句统一带ENGINEInnoDB对已有表执行SHOW TABLE STATUS LIKE physical_exam;看Engine列。删除策略上医疗数据一般先考虑逻辑删除即加del_flag字段标记删除而不是物理DELETE。物理删除会丢失历史轨迹答辩时能主动说出这个设计比单纯“能删数据”加分。5.2 中文写入后显示乱码连接字符集和建表字符集各管一段现象数据在Navicat里看着正常网页或命令行SELECT出来全是“???”手写中文插入直接变问号。原因字符集链路有四段客户端、连接、数据库表的字符集、结果输出。建表用了utf8mb4但JDBC连接串没加characterEncoding参数或命令行工具没执行SET NAMES某个环节用了latin1中文就变问号。这类问题排查起来有点玄学实际就是链路里某个点没有对齐。解决建库统一utf8mb4JDBC连接串写jdbc:mysql://localhost:3306/health_record?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai命令行下执行SET NAMES utf8mb4;再用SHOW VARIABLES LIKE character_set_server;检查服务端变量。机房MySQL全局是latin1时优先在建库语句里声明而不是改全局配置。5.3 LEFT JOIN后的COUNT结果不对NULL计数问题现象统计每个居民的门诊次数SQL写COUNT(department)某居民明明有3条就诊记录却显示0另一人反而正常。原因COUNT(列)只统计非NULL值department字段存了NULL时这条记录会被跳过。很多人以为COUNT(*)和COUNT(列)等价其实只有当列没有NULL时二者才一致。解决统计行数用COUNT(v.visit_id)主键字段不可能为NULL或把department设计成NOT NULL DEFAULT 未分诊。更完整的写法如下SELECT p.profile_id, p.real_name, COUNT(v.visit_id) AS visit_cnt, MAX(v.visit_date) AS last_visit FROM patient_profile p LEFT JOIN visit_record v ON v.profile_id p.profile_id GROUP BY p.profile_id, p.real_name ORDER BY visit_cnt DESC;逻辑说明GROUP BY里带p.real_name是因为它是非聚合列MySQL 8.0默认开启ONLY_FULL_GROUP_BY不带会直接报错。COUNT(v.visit_id)数的是实际存在的行不把NULL统计进去。LEFT JOIN保留没有就诊记录的居民visit_cnt返回0而不是NULL前端展示也省事。5.4 mysqldump备份后存储过程和触发器不见了现象用mysqldump导出了health_record.sql到另一台机器source恢复后表和数据都在但存储过程和触发器一个都不剩页面调用存储过程直接报错。原因mysqldump默认只导出表结构和数据存储过程、触发器、事件需要显式加参数才会包含。许多人只敲了最基本的mysqldump -uroot -p health_record health_record.sql。解决完整备份命令如下mysqldump -uroot -p \ --routines --triggers --events \ --single-transaction \ health_record health_record_full.sql参数说明--routines导出存储过程和函数--triggers导出触发器--events导出定时事件--single-transaction用于InnoDB在线备份不加会锁表。恢复用mysql -uroot -p health_record health_record_full.sql恢复后执行SELECT ROUTINE_NAME FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMAhealth_record;验证对象完整。这是答辩翻车重灾区因为错误提示常常不明显。5.5 密码明文入库演示账号被审计的社死瞬间现象sys_user表里password字段直接存“123456”答辩时老师打开表看到一片明文界面做得再漂亮也白搭。原因为了省事把登录校验写成WHERE usernameadmin AND password123456没有散列也没有加盐。解决应用层用SHA-256把密码转成64位十六进制再INSERT登录时拿输入散列后比对。表结构里的CHAR(64)就是给散列预留的。课设阶段至少做到不平文存储有余力可以加盐再散列。答辩时主动说一句“密码不落明文”会让老师对你的安全意识有印象。6. 答辩前做三件事EXPLAIN、造数据、事务演示6.1 用EXPLAIN验证索引是否被查询真正用到索引建了不等于会用。答辩前对最核心的查询执行EXPLAIN如果typeALL或possible_keys为NULL说明查询没走到索引前面建的联合索引就白做了。EXPLAIN SELECT p.profile_id, p.real_name, e.exam_date, e.bmi FROM patient_profile p JOIN physical_exam e ON e.profile_id p.profile_id WHERE p.id_card 110101199001011234 ORDER BY e.exam_date DESC;看到typeref或const、keyidx_exam_profile_date说明查询走对了路。typeALL时先检查id_card的UNIQUE索引是否创建再看WHERE和JOIN条件字段是否匹配索引最左前缀。宁可花十分钟查EXPLAIN也别在答辩现场猜性能问题。6.2 用存储过程批量造数据演示页面不空转页面只有两三条记录查询性能看不出差别也无法体现索引价值。常见做法是写一个造数存储过程循环插入几万条体检记录DROP PROCEDURE IF EXISTS sp_generate_test_data; DELIMITER $$ CREATE PROCEDURE sp_generate_test_data(IN p_count INT) BEGIN DECLARE i INT DEFAULT 1; DECLARE v_profile_id INT; WHILE i p_count DO INSERT INTO patient_profile(user_id, id_card, gender, birth_date) VALUES (1, CONCAT(TEST, LPAD(i, 12, 0)), IF(i % 2 0, M, F), DATE_ADD(1980-01-01, INTERVAL (i % 10000) DAY)); SET v_profile_id LAST_INSERT_ID(); INSERT INTO physical_exam(profile_id, exam_date, height, weight, systolic, diastolic) VALUES (v_profile_id, DATE_ADD(2023-01-01, INTERVAL (i % 800) DAY), 150 (i % 30), 50 (i % 40), 110 (i % 50), 70 (i % 30)); SET i i 1; END WHILE; END$$ DELIMITER ;参数说明造数的id_card带TEST前缀避开真实身份证校验规则演示而已。身高体重用i % 参数产生有范围的伪随机值血压控制在临床可能范围内。重复跑会因id_card唯一约束报错再次造数前先TRUNCATE相关表或换一组前缀。五万条数据在课设机器上要跑一两分钟提前执行完不要现场等。6.3 两次演示验证事务插入失败不产生脏数据存储过程如果只在Presentation里放代码答辩分量不够。可以用两个数据库会话现场演示会话A调用sp_insert_exam插入一条身高为0的非法数据触发存储过程里的异常处理事务回滚会话B查询physical_exam发现没有任何半条数据残留。再插入一条正常数据档案表里的last_bmi跟着更新。这三十秒比讲十页PPT更有说服力说明你真的理解事务和存储过程而不是只会写CRUD。我自己的习惯是每次完成课设都把字符集、外键、备份、密码、EXPLAIN这五个点查一遍再提交。数据库课设容易翻车的地方往往不在SQL难度而在这些基础细节的最后一晚集中爆发。希望帮到你。本文还有配套的精品资源点击获取
返回列表