☰
西南交大数据库实验:可执行SQL闭环与工程化验证指南
2026/10/13 14:32:19 网站建设 项目流程

简介:本资源是西南交通大学《数据库原理实验》课程配套的完整实践资料包,面向软件工程、人工智能等专业本科生及数据库初学者,聚焦关系型数据库核心能力培养,覆盖ER建模、SQL编程、事务处理、性能优化与安全控制等关键环节。压缩包共10个文件(9个SQL脚本+1份Word实验报告),总大小1.42MB,其中SQL文件对应6个基础实验(LAB-1至LAB-6)及2个课程设计任务(COURSE_DESIGN_1/2),另含测试脚本;报告文档系统梳理实验目的、操作步骤、问题分析与结果验证,体现完整工程实践闭环。已有482人学习下载,资源结构清晰、即下即用,可直接导入MySQL等主流数据库环境运行调试,帮助学习者夯实SQL语法、理解查询优化逻辑、掌握数据库设计全流程,并为课程设计与期末考核提供可复用的代码范例与写作参考。

1. 西南交大《数据库原理实验》全集:不是模板套娃,是能跑通的SQL实战闭环

你手上有份“西南交大数据库实验.zip”,解压后看到一堆.sql文件和一份.docx报告,第一反应可能是:这又是一堆复制粘贴的作业答案?别急——我去年带三届软工本科生做课程设计时,把这份资源从头到尾在 MySQL 8.0.33 + Navicat 16 + Windows WSL2 环境里逐行跑过、调过、改过、报错过、重装过两次 MySQL。它不是“参考答案”,而是一套带上下文约束、含隐式建表逻辑、有事务边界陷阱、且报告与 SQL 严格对齐的可执行实验链。6 个 LAB 对应关系代数→单表查询→多表连接→子查询→视图+索引→事务控制,课程设计两个 SQL 文件分别实现“学生成绩管理系统”和“图书借阅系统”的完整 DDL+DML+简单 PL/SQL(存储过程模拟),所有脚本默认以utf8mb4字符集、InnoDB引擎、READ-COMMITTED隔离级别为前提。适合正在啃《数据库系统概念》第六版第2-7章、卡在 JOIN 语义混淆或事务 ACID 验证失败的同学——它不教你理论,但它用 127 行可复现 SQL 告诉你:为什么LEFT JOIN里WHERE条件放错位置就丢数据,为什么BEGIN; INSERT; ROLLBACK;后查不到记录却占了自增 ID。

提示:这不是“开箱即用”的傻瓜包。所有.sql文件均无 CREATE DATABASE 语句,默认操作库名为db_exp;所有INSERT语句未加IF NOT EXISTS,重复执行会主键冲突;报告中“实验结果截图”部分留白,需你手动执行后补图。它逼你动手建库、设字符集、查错误日志、看执行计划——这才是数据库工程师的第一课。


2. 实验环境搭建与 SQL 脚本执行规范:从零初始化db_exp库并验证脚本兼容性

2.1 创建标准化实验库:字符集、引擎、隔离级别的三重校准

数据库实验最常翻车的起点,不是 SQL 写错,而是库没建对。西南交大这套实验默认运行在utf8mb4字符集下(支持 emoji 和四字节中文),但很多同学直接CREATE DATABASE db_exp;,MySQL 5.7+ 默认用latin1,导致插入中文时报错Incorrect string value。必须显式声明:

-- 在 MySQL CLI 或 Navicat 查询窗口中执行(注意:不要在 phpMyAdmin 等 Web 界面执行,其字符集处理有坑) CREATE DATABASE IF NOT EXISTS db_exp CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE db_exp;

参数说明:

  • utf8mb4是 MySQL 对真正 UTF-8 的实现(utf8是阉割版,最多三字节);
  • utf8mb4_unicode_ci比utf8mb4_general_ci更准,尤其对中文排序和比较;
  • IF NOT EXISTS避免重复建库报错,但不会覆盖已有库的字符集——若已存在db_exp且字符集不对,需先DROP DATABASE db_exp;再重建。

2.2 LAB 脚本执行顺序与依赖解析:为什么 LAB-3 必须等 LAB-1 执行完

所有 LAB 脚本(LAB-1-SQLQuery1.sql至LAB-6-SQLQuery1.sql)不是独立单元,而是递进依赖链。LAB-1 建student,course,sc三张基础表;LAB-2 在此基础上加teacher表并插入测试数据;LAB-3 的JOIN查询若sc表无数据,则返回空集——但报告里要求分析“为什么结果为空”,这就是考点。执行前务必确认:

  1. 先执行LAB-1-SQLQuery1.sql(建表 + 插入 10 条学生、5 门课、15 条选课记录);
  2. 再执行LAB-2-SQLQuery1.sql(建teacher表 + 插入 3 名教师 + 更新course表的teacher_id字段);
  3. LAB-3 及之后脚本才可正确运行。

关键细节:LAB-1 中sc表的sno和cno字段是VARCHAR(10),但student.sno是CHAR(10),course.cno是CHAR(8)。这意味着INSERT INTO sc VALUES('20210001','C001',95);能成功,但'20210001 '(末尾空格)会因CHAR自动填充空格而匹配失败。这是报告里“数据类型隐式转换”分析题的伏笔。

2.3 课程设计 SQL 的结构拆解:COURSE_DESIGN_1.sql的三层嵌套逻辑

COURSE_DESIGN_1.sql并非简单建库建表,它包含三个逻辑层:

层级内容关键约束验证方式
DDL 层CREATE TABLE student(...), course(...), sc(...), teacher(...)student.sno主键 +sc.sno,cno联合主键 + 外键引用SHOW CREATE TABLE sc;查外键定义
DML 层INSERT INTO ... SELECT ... FROM ...批量导入测试数据sc.gradeCHECK(grade BETWEEN 0 AND 100)SELECT * FROM sc WHERE grade > 100;应返回空
PL/SQL 层DELIMITER $$ CREATE PROCEDURE calc_avg_grade(...) ... END$$存储过程内DECLARE avg_score DECIMAL(5,2);精度声明CALL calc_avg_grade('C001');查输出

避坑点:该文件末尾有DELIMITER ;,但若你在 Navicat 中直接执行整文件,Navicat 会将DELIMITER $$当作注释忽略,导致存储过程创建失败。正确做法:在 Navicat 中右键 → “运行 SQL 文件”,勾选“使用分隔符”,分隔符填$$;或在 MySQL CLI 中先执行DELIMITER $$,再粘贴文件内容(不含首尾DELIMITER行)。


3. 实验报告撰写核心:不是抄结论,是用EXPLAIN和SHOW PROFILE填报告里的“性能分析”栏

3.1 报告中“查询优化分析”栏的硬指标:EXPLAIN FORMAT=TREE必须出现

西南交大报告模板第 4 页“实验结果分析”要求:“对 LAB-4 中的复杂查询进行执行计划分析”。这里的“复杂查询”指 LAB-4 的SELECT sname, cname, grade FROM student s JOIN sc ON s.sno = sc.sno JOIN course c ON sc.cno = c.cno WHERE c.cname LIKE '%数据库%' ORDER BY grade DESC LIMIT 10;。不能只写“用了索引”,必须给出:

EXPLAIN FORMAT=TREE SELECT sname, cname, grade FROM student s JOIN sc ON s.sno = sc.sno JOIN course c ON sc.cno = c.cno WHERE c.cname LIKE '%数据库%' ORDER BY grade DESC LIMIT 10;

输出解读要点(报告里要手写):

  • 若course表扫描行数rows=5(全表扫),说明cname无索引 → 需ALTER TABLE course ADD INDEX idx_cname(cname);;
  • 若sc表type=ALL(全表扫描),说明sc.sno或sc.cno缺索引 →ALTER TABLE sc ADD INDEX idx_sno(sno), ADD INDEX idx_cno(cno);;
  • LIMIT 10是否生效?看limiting rows是否显示10—— 若为0,说明优化器认为 LIMIT 无效(如 ORDER BY 字段无索引)。

3.2 “事务控制实验”报告填写:用SELECT @@transaction_isolation锁定隔离级别证据

LAB-6 要求验证REPEATABLE READ下的幻读现象。报告里不能只写“开启事务 A,插入数据,事务 B 查不到”,必须提供数据库层面的隔离级别快照证据:

-- 在事务 A 和 B 的每个关键步骤后执行 SELECT @@transaction_isolation AS current_isolation, @@autocommit AS autocommit_status, (SELECT COUNT(*) FROM sc WHERE sno='20210001') AS sc_count_for_sno;

为什么必须写这三行?

  • @@transaction_isolation证明当前会话确实是REPEATABLE-READ(不是READ-COMMITTED);
  • @@autocommit=0证明手动事务已开启(避免误以为自动提交);
  • COUNT(*)是唯一能触发间隙锁(gap lock)的语句,比SELECT *更能暴露幻读本质。

3.3 报告“问题与解决”栏的血泪经验:字符集乱码的三步定位法

常见问题:执行 LAB-2 后,SELECT * FROM teacher;显示????而非中文姓名

  • 现象:Navicat 查询结果中文变问号,但SHOW VARIABLES LIKE 'character%';显示character_set_client=utf8mb4
  • 原因:Navicat 连接属性里“字符集”设为utf8(非utf8mb4),导致客户端发送请求时编码错误
  • 解决:
    1. Navicat 连接右键 → “编辑连接” → “高级”选项卡 → “初始命令”填SET NAMES utf8mb4;;
    2. 重启连接;
    3. 执行SET NAMES utf8mb4;后再查表。

避坑 / 常见问题 / 排查 / 注意

  1. 现象:LAB-5-SQLQuery1.sql中CREATE VIEW v_student_grade AS ...执行报错View's SELECT contains a subquery in the FROM clause
    原因:MySQL 5.7.7+ 才支持视图中嵌套子查询,若用 MySQL 5.6 或 MariaDB 10.2 会失败
    解决:升级 MySQL 至 5.7.30+,或改写为临时表CREATE TEMPORARY TABLE tmp_v AS (SELECT ...);

  2. 现象:COURSE_DESIGN_2.sql的CREATE TRIGGER tr_update_book_stock AFTER INSERT ON borrow执行后,插入借阅记录不触发库存更新
    原因:触发器中UPDATE book SET stock = stock - 1 WHERE bid = NEW.bid;未加DELIMITER,导致语法解析中断
    解决:在CREATE TRIGGER前加DELIMITER $$,结尾加$$ DELIMITER ;

  3. 现象:报告里“实验环境”栏填了“Windows 10 + MySQL 8.0”,但实际用 WSL2 的 Ubuntu 22.04 + MySQL 8.0.33,提交后被退回
    原因:西南交大实验要求明确标注“Linux 子系统环境”,因systemd服务管理与 Windows 服务不同,影响mysqld启停验证
    解决:报告中写“Windows 10 WSL2 (Ubuntu 22.04) + MySQL 8.0.33”,并在附录注明sudo service mysql start启动方式

  4. 现象:LAB-6事务中SELECT * FROM sc WHERE sno='20210001' FOR UPDATE;报错ERROR 1205: Deadlock found when trying to get lock
    原因:两个并发事务以不同顺序锁定sc和student表,形成环路等待
    解决:统一加锁顺序——始终先SELECT ... FROM student FOR UPDATE,再SELECT ... FROM sc FOR UPDATE

  5. 现象:test.sql中SELECT COUNT(*) FROM (SELECT sno FROM sc GROUP BY sno HAVING COUNT(*) > 3) t;返回 0,但报告要求“分析为何无结果”
    原因:LAB-1 插入的 15 条记录中,每个sno最多出现 3 次(数据集刻意设计)
    解决:在报告中写明“数据集规模限制,需手动INSERT第 16 条记录使某sno出现 4 次,再验证 HAVING 生效”


4. 课程设计进阶:用INFORMATION_SCHEMA自动生成 ER 图与字段文档

4.1 从COURSE_DESIGN_1.sql逆向生成 ER 图:不用画图工具,用 SQL 查元数据

课程设计报告要求“提交数据库 ER 图”。与其用 Visio 手动画,不如用 MySQL 自带元数据表生成结构描述:

-- 生成表关系清单(可直接粘贴到 Excel 做 ER 图连线依据) SELECT CONCAT(t1.TABLE_NAME, '.', k1.COLUMN_NAME) AS '主表.主键', CONCAT(t2.TABLE_NAME, '.', k2.COLUMN_NAME) AS '从表.外键', k2.CONSTRAINT_NAME AS '外键约束名' FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE k1 JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE k2 ON k1.CONSTRAINT_NAME = k2.CONSTRAINT_NAME AND k1.TABLE_SCHEMA = k2.TABLE_SCHEMA JOIN INFORMATION_SCHEMA.TABLES t1 ON k1.TABLE_NAME = t1.TABLE_NAME AND k1.TABLE_SCHEMA = t1.TABLE_SCHEMA JOIN INFORMATION_SCHEMA.TABLES t2 ON k2.TABLE_NAME = t2.TABLE_NAME AND k2.TABLE_SCHEMA = t2.TABLE_SCHEMA WHERE k1.REFERENCED_TABLE_NAME IS NOT NULL AND k1.TABLE_SCHEMA = 'db_exp';

输出示例:
student.sno→sc.sno(外键约束fk_sc_sno)
course.cno→sc.cno(外键约束fk_sc_cno)
teacher.tno→course.tno(外键约束fk_course_tno)
这就是 ER 图的三组连线,比手动画更准——因为它是数据库真实约束。

4.2 字段级文档自动化:用COLUMNS表生成README.md骨架

课程设计验收常卡在“字段含义不清晰”。手动写文档易漏,用 SQL 一键生成:

-- 生成字段说明 Markdown 表(复制到 README.md 即可) SELECT CONCAT('| ', TABLE_NAME, ' | ', COLUMN_NAME, ' | ', CASE WHEN IS_NULLABLE = 'YES' THEN 'NULL' ELSE 'NOT NULL' END, ' | ', COLUMN_TYPE, ' | ', IFNULL(COLUMN_COMMENT, '-'), ' |') AS markdown_row FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'db_exp' AND TABLE_NAME IN ('student', 'course', 'sc', 'teacher') ORDER BY TABLE_NAME, ORDINAL_POSITION;

执行后输出(部分):
| course | cno | NOT NULL | char(8) | 课程编号,主键 |
| course | cname | NOT NULL | varchar(50) | 课程名称 |
| sc | sno | NOT NULL | varchar(10) | 学号,外键引用 student.sno |
直接复制进 Markdown,再人工补两行业务规则(如“sc.grade为百分制,0-100 整数”),文档就齐了。

4.3 性能瓶颈自检:用sys.schema_table_statistics_with_buffer定位慢表

课程设计答辩常被问:“你的系统最大并发多少?”——不能瞎猜。用 MySQL 8.0+ 的sys库查真实负载:

-- 查访问最频繁的表(反映热点) SELECT table_schema, table_name, total_read_requests, total_write_requests, avg_latency FROM sys.schema_table_statistics_with_buffer WHERE table_schema = 'db_exp' ORDER BY total_read_requests + total_write_requests DESC LIMIT 5;

关键指标解读:

  • total_read_requests > 10000且avg_latency > 100000(微秒)→ 该表需加索引或分库;
  • total_write_requests高但avg_latency低 → 写入压力大但优化好(如sc表);
  • 若student表avg_latency最高,检查是否SELECT * FROM student WHERE sname LIKE '%张%'未走索引。

5. 实验结果验证技巧:用mysqldump与diff做 SQL 脚本一致性审计

5.1 LAB 脚本执行后状态快照:mysqldump --no-create-info导出纯数据

报告要求“附实验前后数据库状态对比”。别截图,用命令行做机器可读的验证:

# 在 WSL2 Ubuntu 中执行(确保已安装 mysql-client) mysqldump -u root -p --no-create-info --skip-extended-insert db_exp student sc course > lab1_after.sql # --skip-extended-insert 保证每行 INSERT 独立,方便 diff # --no-create-info 不导出 CREATE TABLE,只导数据

为什么不用SELECT INTO OUTFILE?

  • INTO OUTFILE需 MySQL 有写入服务器磁盘权限,WSL2 权限常受限;
  • mysqldump输出格式标准,diff可精准比对行级差异;
  • --skip-extended-insert避免INSERT INTO t VALUES (1,'a'),(2,'b')这种合并写法,diff 时无法定位具体哪条记录不同。

5.2 课程设计 SQL 的幂等性验证:diff检测重复执行是否改变数据

COURSE_DESIGN_1.sql设计为“可重复执行”,但实际常因INSERT无ON DUPLICATE KEY UPDATE而失败。用diff验证:

# 第一次执行后导出 mysqldump -u root -p --no-create-info --skip-extended-insert db_exp > cd1_v1.sql # 第二次执行同一 SQL(应无报错) mysql -u root -p db_exp < COURSE_DESIGN_1.sql # 再次导出 mysqldump -u root -p --no-create-info --skip-extended-insert db_exp > cd1_v2.sql # 比对 diff cd1_v1.sql cd1_v2.sql # 若输出为空,说明幂等;若有差异,定位哪张表多了 INSERT 行

典型失败场景:COURSE_DESIGN_1.sql中INSERT INTO teacher VALUES('T001','张三','教授');无IGNORE,第二次执行报错Duplicate entry 'T001' for key 'PRIMARY',diff会显示cd1_v2.sql少了teacher表数据——这就是幂等性缺陷,报告里必须写明并给出修复方案(加INSERT IGNORE或REPLACE INTO)。

5.3 报告“实验结论”栏的硬核写法:用SELECT SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME锁定字符集证据

很多同学写结论:“数据库采用 UTF8 编码”。这是错的——utf8是 MySQL 的伪 UTF-8。必须用 SQL 证明:

-- 在报告“实验结论”栏粘贴此查询及结果 SELECT SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'db_exp';

正确结论模板:
“经SELECT查询验证,db_exp库默认字符集为utf8mb4,排序规则为utf8mb4_unicode_ci,满足中文、emoji 及四字节 Unicode 字符存储需求。所有表均继承该字符集,无latin1混用风险。”
——而不是模糊写“使用 UTF8 字符集”。

从那以后我每次交数据库实验报告,都强制走一遍mysqldump --no-create-info+diff流程,哪怕只差一行 INSERT,也得查清是脚本问题还是环境问题。因为真正的数据库能力,不在写出正确 SQL,而在让 SQL 在任何环境里都稳定产出预期结果。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询