☰
数据库原理课后习题答案实战:从关系代数到MySQL并发控制
2026/10/12 1:02:38 网站建设 项目流程

简介:《数据库原理及应用》课后习题答案文档,面向数据库初学者、备考学生与高校教师,可用来核对课后作业、梳理核心概念与解题思路。压缩包内为1个doc文档,大小752KB,内容聚焦数据库基础,涵盖数据库(DB)、数据库系统(DBS)、数据库管理系统(DBMS)、实体、属性、关键字等名词解释,以及概念数据模型与关系模型要点。文档详细剖析了逻辑数据独立性、物理数据独立性及实体间一对一、一对多、多对多三类联系,附有判断题对错答案和简答题解答,如数据管理技术发展历程、文件系统与数据库系统的区别与联系等。读者能借此系统掌握数据库原理核心概念,快速区分易混淆定义,特别适合期末复习、课后自测与备课参考。该资源已有244人学习下载。

1. 一份“数据库原理及应用课后习题答案.doc”到底能帮你补什么

“数据库原理及应用课后习题答案.doc”最容易被当成考前抄作业的救星,但我见过太多人抄完一遍,考试遇到“为什么这个SQL不走索引”还是懵。这份答案真正值钱的不是那几行标准结果,而是它把关系代数、SQL、范式、并发控制浓缩成了一套可以逐题验证的练习清单。下面按我自己的使用习惯来拆:先立理论框架,再建一个最小库把题目复现出来,用执行计划和结果集自证对错,最后绕开五个高频翻车点。适合正在补课的学生、带实验课的助教,以及想系统过一遍数据库基础的一线开发。

2. 读懂课后习题答案之前,先搞清楚数据库原理课的四块硬骨头

2.1 关系代数与关系模型:答案里“用自然语言描述查询”的底层语言

课后习题里最常出现的一类题是“用关系代数或SQL表达:查询选修了某课程的学生的姓名”。这题看着简单,实际考的是两个基本功:先把自然语言翻译成关系代数里的一系列运算(选择、投影、连接、除),再把它翻译成SQL。很多人直接跳过关系代数去背SQL,于是遇到“查询选修了全部课程的学生的学号”这种需要除运算的题就会卡住。关系代数不是考试才用的抽象概念,它决定你对SQL的理解能不能走出死记硬背。

MySQL里没有直接的除法运算符,常见做法是用NOT EXISTS做差集模拟。一份好答案会告诉你“结果集应该长什么样”,但不会替你解释为什么这一步要叫作“除运算”。我一般会把这类题按三步走:先确定参与运算的关系,再写出候选结果集,最后用自然语言反读一遍确认没有漏掉“全部、至少、不包含”这类量词。这里最容易翻车的地方是漏条件,比如把“选修了全部课程”写成“选修了至少一门课程”。

关系代数还有一个隐藏考点是连接条件。自然连接、等值连接、外连接在结果集形态上差别很大,习题答案里经常用“哪些学生没选课”来考外连接。你如果只看答案不看运算过程,下次换个表结构照样不会举一反三。学这块的硬标准是:拿到一段自然语言描述,能独立写出关系代数表达式,并能说出每一步去掉了哪些行、保留了哪些列。

2.2 SQL与完整性约束:答案不是背语法,是搞清数据操纵的对象

SQL题在课后习题里占比最大,但教材答案往往只给最终查询,不给设计理由。以“增删改查”里的“增”为例,插入数据时主键冲突、外键不存在、唯一约束重复都是数据库会直接拒绝的硬条件。一份只给INSERT语句的答案,如果没讲清楚这些约束,你在自己的电脑上跑就会报错——“为什么答案能跑,我跑不了”十有八九是约束条件有出入。

完整性约束里最值得花时间的是外键的参照动作。ON DELETE CASCADE和ON DELETE SET NULL在删除父表数据时行为完全不同,课后习题经常在这里埋坑。另一个学生容易忽略的是唯一约束和普通索引的区别:唯一约束不仅加速查询,还阻止重复值写入,这在设计“用户表”和“订单表”时尤其关键。

SQL的另一个大项是权限管理。GRANT和REVOKE在习题答案里常作为独立题目出现,但多数人只是背语句。我的建议是把权限题和“为什么不能删数据”连起来理解:一个连接用户能不能建表、能不能删除记录,取决于它的权限集合。数据库原理考试里所谓的“授权题”,本质上考的是你对角色、权限层级和WITH GRANT OPTION的理解。

2.3 范式与函数依赖:候选键没找对,题题都错

范式判断是课后习题里最容易被答案带偏的部分,因为最终结论是“第几范式”,但推导过程因人而异。判断NF的第一步永远是找候选键,候选键找错,后面全错。找候选键的步骤是:先画函数依赖图,找出从未出现在依赖右侧的属性集,再验证它能否推导出全部属性。很多答案直接给结论“属于2NF不属于3NF”,却不展示候选键的求解过程,这是最坑的地方。

函数依赖里有几个边界概念要分清:部分依赖、传递依赖、完全依赖。2NF要求消除非主属性对候选键的部分依赖,3NF要求消除传递依赖,BCNF则要求每个决定因素都是候选键。课后习题常见题型是给一个关系模式和一组函数依赖,让你规范化到3NF或BCNF。我看过不少学生拿着答案硬套,结果在无损分解和高保持依赖上栽跟头。

无损分解的判定标准是:分解后能通过自然连接恢复原关系,没有额外行也没有丢行。判断工具是全局依赖检查以及经典的“追踪算法”。如果一份课后答案只给分解结果不给验证方法,那它只能帮你验证最终形态,不能帮你建立判断逻辑。考试时时间紧张,最快的自检办法是先把分解后的每个关系写出来,再做一次自然连接,看能不能还原出原表中的每一行。

2.4 事务、并发控制与恢复:把理论题当成事故复盘

ACID四个特性在课后习题里通常出判断题和简答题,但真正难的是并发控制部分。题目常给两个事务的调度序列,问有没有脏读、不可重复读、幻读,或者问是否会死锁。这类题按“现象→原因→规则”来答最稳:先描述你看到了什么异常,再指出是哪个隔离级别没拦住,最后说明应该用哪个隔离级别或加什么锁。

锁是这块的核心。共享锁和排他锁的兼容矩阵、两段锁协议、锁升级与锁等待,都是高频考点。“数据库并发锁”和“数据库死锁”两个标签经常一起出现,因为死锁本质上是两个事务各自持有一把锁、又同时去争抢对方手里的锁。习题答案里如果用“等待图”来判断死锁,那是最直观的做法:画出节点和等待边,看有没有环。

日志与恢复机制在答案里容易被简写为“REDO和UNDO”,但你要知道它们各自的服务对象:REDO用于重做已提交但未落盘的事务,UNDO用于回滚未提交事务。检查点则是为了减少恢复时扫描日志的范围。理解这几个概念后,再看答案里的“故障恢复流程图”就不会一头雾水。

3. 把课后习题答案反推成实验:用MySQL 8.0复现“学生-课程-选课”最小库

3.1 建库建表:把答案里的关系模式翻译成可运行的DDL

以习题里出现频率最高的“学生-课程-选课”关系模式为例。先建库,再建三张表:student、course、sc(选课表)。注意字符集和排序规则要明确charset,否则后面插入中文姓名时可能出现乱码。

CREATE DATABASE IF NOT EXISTS school DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE school; CREATE TABLE student ( sno CHAR(9) PRIMARY KEY COMMENT '学号', sname VARCHAR(20) NOT NULL COMMENT '姓名', ssex CHAR(2) COMMENT '性别', sage SMALLINT COMMENT '年龄', sdept VARCHAR(20) COMMENT '所在系' ) ENGINE=InnoDB; CREATE TABLE course ( cno CHAR(4) PRIMARY KEY COMMENT '课程号', cname VARCHAR(40) NOT NULL COMMENT '课程名', cpno CHAR(4) COMMENT '先修课程号', credit SMALLINT COMMENT '学分' ) ENGINE=InnoDB; CREATE TABLE sc ( sno CHAR(9) COMMENT '学号', cno CHAR(4) COMMENT '课程号', grade DECIMAL(5,2) COMMENT '成绩', PRIMARY KEY (sno, cno), FOREIGN KEY (sno) REFERENCES student(sno), FOREIGN KEY (cno) REFERENCES course(cno) ) ENGINE=InnoDB;

这里的逻辑是先定义主键和业务字段,再用外键把选课表和两张主表连起来。CHAR和VARCHAR的选择要按实际需求来:学号长度固定用CHAR,姓名长度可变用VARCHAR。PRIMARY KEY (sno, cno) 的组合主键保证同一学生同一课程只能有一条成绩记录,这是习题里“完整性约束”的落地表现。

ENGINE=InnoDB 是必须的,因为外键约束和事务支持都依赖这个引擎。如果用默认的MyISAM,外键定义不会生效,后面做事务练习也会失败。字段上的COMMENT注释是给后面的自己看的,做课程设计交接时尤其有用。

建完表后可以顺手验证一下表结构是否正确,用SHOW CREATE TABLE sc;查看实际建表语句。如果发现外键缺失或字符集不对,在插入数据前修改代价最低。这相当于给整个实验打了“后悔药”。

3.2 数据操纵:把习题里的查询用增删改查跑出结果

建表之后要造数据。课后习题一般会给少量示例数据,我建议按“最小但能覆盖边界”的原则插入:至少保证有一个学生选修了全部三门课,有一个学生一门都没选,有一门课没人选。这样查询类题目才能测出连接、分组、外连接的真实差异。

INSERT INTO student (sno, sname, ssex, sage, sdept) VALUES ('200100101', '张一', '男', 20, '计算机系'), ('200100102', '李二', '女', 19, '计算机系'), ('200100103', '王三', '男', 21, '数学系'); INSERT INTO course (cno, cname, cpno, credit) VALUES ('C001', '数据库', NULL, 4), ('C002', '数据结构', 'C001', 3), ('C003', '操作系统', 'C001', 4); INSERT INTO sc (sno, cno, grade) VALUES ('200100101', 'C001', 88.00), ('200100101', 'C002', 75.50), ('200100101', 'C003', 92.00), ('200100102', 'C001', 61.00);

插入逻辑按主表到从表的顺序来,先student后course再sc,因为sc里的外键值必须在主表里存在。cpno字段用来模拟先修课程,这里让“数据结构”和“操作系统”都以“数据库”为先修课,后续做自连接查询时会用到。

常见查询题是“查询选修了数据库课程且成绩大于等于80分的学生姓名”。这道题考的是两表连接加过滤条件,关键是先连接再筛选,还是先筛选再连接。在MySQL优化器处理下结果一样,但从可读性上讲,先缩小数据范围再连接更清晰。

SELECT s.sname, sc.grade FROM sc JOIN student s ON sc.sno = s.sno JOIN course c ON sc.cno = c.cno WHERE c.cname = '数据库' AND sc.grade >= 80 ORDER BY sc.grade DESC;

JOIN顺序我一般写成“从事实表sc出发,再关联维度表”,因为选课记录是查询的主入口。WHERE里的两个条件是等值筛选,一个锁定课程名,一个锁定成绩下限,逻辑上相当于关系代数里的选择运算。ORDER BY是题目里“按成绩降序”的要求,没要求就别加,加了可能会影响执行计划的稳定性。

分组统计题是另一个重点。“统计各课程选修人数”对应GROUP BY + COUNT,如果还要求“只显示选课人数大于1的课程”,就需要HAVING做组后过滤。GROUP BY和HAVING的配合是习题答案里最容易写漏的地方——很多人把条件误放到WHERE里,但WHERE在分组前执行,无法过滤聚合结果。

3.3 事务练习:用隔离级别和锁把并发控制的题目跑出真实现象

理论题的“脏读、不可重复读、幻读”光靠背很难记住,直接开两个终端会话跑一遍最有效。我用MySQL演示一个不可重复读场景:会话A开启事务后读取成绩,会话B修改成绩并提交,会话A再读会发现数据变了,这就是不可重复读。

先设置隔离级别,再开启事务。注意SET TRANSACTION要写在START TRANSACTION前面才会对当前事务生效。

-- 会话A SET TRANSACTION ISOLATION LEVEL READ COMMITTED; START TRANSACTION; SELECT grade FROM sc WHERE sno = '200100101' AND cno = 'C001'; -- 此时读到 88.00,然后不要提交,切换到会话B -- 会话B START TRANSACTION; UPDATE sc SET grade = 90.00 WHERE sno = '200100101' AND cno = 'C001'; COMMIT; -- 回到会话A再次执行上面的SELECT -- READ COMMITTED 隔离级别下会读到 90.00,说明不可重复读发生了

参数说明:ISOLATION LEVEL READ COMMITTED 表示事务只能读取已提交数据,但两次独立读之间可能有其他事务提交新值。要避免不可重复读,把隔离级别改成 REPEATABLE READ,InnoDB在RR下通过快照读保证事务内多次读取结果一致。MySQL的默认隔离级别就是REPEATABLE READ,所以很多人在默认配置下测不出不可重复读,这就是答案和实验现象对不上的常见原因。

锁的实验也值得做。SELECT ... FOR UPDATE会加排他锁,两个事务同时对同一行加锁就会阻塞,超时后报死锁或锁等待超时错误。这个现象直接在终端里就能看到:会话A执行FOR UPDATE,会话B再对同一行执行FOR UPDATE,B会一直等待直到A提交或innodb_lock_wait_timeout到期。

-- 会话A START TRANSACTION; SELECT * FROM sc WHERE sno = '200100101' AND cno = 'C001' FOR UPDATE; -- 不提交 -- 会话B SET innodb_lock_wait_timeout = 5; SELECT * FROM sc WHERE sno = '200100101' AND cno = 'C001' FOR UPDATE; -- 等待约5秒后报错: Lock wait timeout exceeded

这里innodb_lock_wait_timeout的单位是秒,默认值是50秒,演示时改小到5秒可以让现象快速出现。做完实验记得回滚或提交,否则连接持有的锁会影响后续所有练习。

4. 从“抄答案”到“造答案”:手写一份能自证对错的习题答案笔记

4.1 给每道题标注知识域:不按章节排,按能力项排

课后习题答案的目录通常按教材章节编排,但复习时按知识域重新组织效率更高。我会把题目拆成五类:关系代数题、SQL查询题、完整性约束题、范式规范化题、事务并发题。每做完一道题,在笔记里记三件事:原题考察的知识点、我写错的步骤、正确结果集的特征。用一张表格记录最直观。

题号知识域我的错误点正确做法复现状态
3-12关系代数除运算漏写NOT EXISTS用双重NOT EXISTS模拟已在MySQL跑通
4-7SQL查询HAVING写成了WHERE聚合条件只能放HAVING已跑通
6-3范式候选键少找一个先画函数依赖图再验证手写验证

这个表格的作用不是记录“我做过什么题”,而是暴露“我哪里会做错”。我见过太多人刷完一遍答案,错题本上干干净净,考试时在原题上再翻一次车。按知识域重新分组后,你会发现自己的错误高度集中在某个能力块,接下来只需针对性补那一个点。

4.2 用执行计划和结果集双验证:怎么确认自己写的SQL是对的

判断一道SQL题做得对不对,不能只盯着结果集。结果对只能说明“这组数据下碰巧对”,换个数据分布可能就漏行或重复行。我习惯双验证:先看结果集是否符合题意,再用EXPLAIN看执行计划确认没有全表扫描等隐藏问题。

-- 题目:查询没有选修任何课程的学生姓名 -- 方案一:LEFT JOIN + IS NULL EXPLAIN SELECT s.sname FROM student s LEFT JOIN sc ON s.sno = sc.sno WHERE sc.sno IS NULL; -- 方案二:NOT EXISTS EXPLAIN SELECT s.sname FROM student s WHERE NOT EXISTS (SELECT 1 FROM sc WHERE sc.sno = s.sno);

两个方案语义等价,但执行计划可能不同。当sc表有索引且数据量较大时,NOT EXISTS往往走索引查找更高效;LEFT JOIN在某些版本里会先做全表扫描再做过滤。验证时不仅要看id、type、key这三列,还要注意Extra列里有没有“Using temporary”或“Using filesort”,出现这两个词说明这个SQL在数据量大时会拖慢性能。

结果集验证也有技巧:把“选修了课程的”和“没选修课程的”两个查询结果合并,看是否恰好等于学生总数。这种“完整性自检”比肉眼确认几行数据可靠得多。我一般会在笔记里把验证SQL也写进去,下次翻看时能快速知道当时为什么认为这是对的。

4.3 把“数据库原理及应用课后习题答案”整理成可用的速查卡

整理到最后,一份好的习题答案笔记应该浓缩成几张速查卡:范式判定表、隔离级别对比表、锁类型表。这三张表是考试和面试都高频使用的“硬通货”,比零散的题目答案更有迁移价值。

隔离级别脏读不可重复读幻读锁机制
READ UNCOMMITTED可能可能可能读不加锁
READ COMMITTED不会可能可能读已提交快照
REPEATABLE READ不会不会可能(InnoDB间隙锁可避免)快照读+间隙锁
SERIALIZABLE不会不会不会所有读都加锁

范式速查就按“主属性是否部分依赖、非主属性是否传递依赖、决定因素是否全为候选键”三连问来判定。第一问不过就是1NF,第二问不过就是2NF,第三问不过就是3NF或BCNF之间的分界。把这些整理成卡片后,“数据库原理及应用课后习题答案”就不只是一份静态文档,而是你随时可查的排错工具。

5. 数据库原理及应用课后习题答案的5个典型翻车现场与排查方法

5.1 现象:外键数据删不掉,答案里的DELETE语句一执行就报错

很多习题答案直接写“删除学生记录”,但你的表结构里sc表通过外键引用了student表的sno。此时执行DELETE FROM student WHERE sno='200100101';会触发外键约束错误,因为还有选课记录引用这行。

原因:删除主表数据时,从表仍有匹配记录,默认约束行为是RESTRICT,即阻止删除。

解决:根据题意选一个策略。如果课程设计里要求“学生退学后保留选课历史”,外键改成FOREIGN KEY (sno) REFERENCES student(sno) ON DELETE SET NULL;如果要求“级联清空选课记录”,用ON DELETE CASCADE。改外键需要先删掉旧约束再重建,早期的建表设计直接决定后续操作是否顺利。

5.2 现象:同一段SQL在MySQL能跑通,换到Oracle或达梦数据库就报错

习题答案如果只针对单一数据库环境,切换到另一个数据库产品时字符串拼接、分页语法、空值判断都会出问题。MySQL的LIMIT在Oracle里不认,Oracle的ROWNUM在MySQL里也不存在,“达梦数据库”和“人大金仓”这类国产数据库在兼容性上各有各的方言。

原因:SQL标准只定义了核心语法,数据库产品在分页、拼接、日期函数上大量方言化。

解决:先确认这份答案标注的数据库版本。做兼容性实验时,把LIMIT换成语义等价的标准写法,比如用FETCH FIRST或子查询套ROWNUM。更稳的做法是把“查询前N条”这种需求抽象成工具函数,每个数据库各自实现一遍接口,上层SQL共用同一套逻辑。数据库连接池在切换数据源时,也要同步检查驱动版本和连接串参数。

5.3 现象:并发控制题的答案和书上不一致,一个说“不会脏读”一个说“可能脏读”

课后习题答案默认的隔离级别可能和你的数据库实际配置不同。MySQL默认是REPEATABLE READ,Oracle默认是READ COMMITTED,如果答案按Oracle默认值推导,你在MySQL里复现就会对不上。

原因:不同数据库的默认隔离级别不同,习题答案没有显式声明前提条件。

解决:讨论并发现象前先锁定隔离级别。在MySQL里执行SELECT @@transaction_isolation;查看当前值,需要时用SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;对齐题目环境。做实验时开两个会话窗口,一个改一个读,现象比理论推导直观得多。这个翻车点尤其坑人,因为它不是“你写错了”,而是“环境假设不同”。

5.4 现象:范式判断总错,答案说属于3NF,我却判成2NF

问题几乎都出在候选键识别上。一个关系模式可能有多个候选键,只找出一个就急着判断,会把部分依赖误判成完全依赖。

原因:漏掉了藏在函数依赖右侧的属性出现在左侧的组合候选键。比如依赖集{A→B, C→B, AC→D},候选键是AC组成的组合键,不是单独A或C。

解决:按流程走。第一步列出全部属性;第二步找出每个属性的依赖路径;第三步验证属性组合的闭包能否覆盖全部属性。把候选键全部列清楚后,再看各非主属性是否对某个候选键存在部分依赖。如果你手写的推导过程和答案只看结论对不上,把候选键求解过程写出来对比,通常能定位到具体断点。

5.5 现象:答案里的INSERT能成功执行,但顺序一换就报错或数据丢失

SQL里某些语句会触发隐式提交,比如DDL语句、LOAD DATA、部分管理操作。如果在事务中间执行了这些语句,当前事务会先被提交,后续回滚操作就失效了。

原因:答案文档给出的是独立语句,没有考虑事务上下文。你把它拼进一个长事务,隐式提交把前面的操作写死,后面的操作回滚不了。

解决:养成“事务只放DML,不放DDL”的写代码习惯。需要修改表结构时,先把当前事务提交确认,再执行ALTER TABLE,或者把DDL放到事务开始之前。排查方法是看事务最后执行ROLLBACK后,哪些数据仍然存在,存在的那部分就是被隐式提交提前“焊死”的。

6. 把习题答案练成的能力迁移到生产:EXPLAIN、死锁日志与慢查询

6.1 用EXPLAIN验证课后习题的查询是否走索引

课后题里的WHERE条件如果直接落在索引列上,执行计划会显示type为ref或range;如果条件写在无索引列上,type就是ALL,意味着全表扫描。生产环境里慢查询十有八九是这种问题。给sc表的sno、cno建好复合索引后,再执行EXPLAIN SELECT ... WHERE sno='200100101';,看到key列用的索引名就知道走对了。

6.2 把死锁理论题做成实验:观察锁等待和innodb_lock_wait_timeout

死锁实验我建议在课后习题阶段就做一遍:两个事务分别更新两条记录,但顺序相反,最终互相等待。做完后查SHOW ENGINE INNODB STATUS\G里的LATEST DETECTED DEADLOCK段落,看两个事务分别持有什么锁、等待什么锁。这条读日志的习惯在生产环境排查“数据库死锁”问题时能直接套用,比靠猜快很多。

6.3 用视图和存储过程的题目当模板,给课程设计搭后端接口

习题里的视图题可以改造成课程设计里的报表接口,存储过程题可以改造成后端批量入库逻辑。把视图创建语句封装好,应用层只需SELECT * FROM v_score_report;,复杂查询细节全收敛到数据库端。这是我做数据库课程设计时最常用的做法:先按习题把视图跑通,再给它加参数、加权限控制,逐步演进成可交付的功能模块。坚持这样练下来,你会发现课后习题不是负担,而是一套现成的实验手册。希望这些方法和踩坑记录能帮你在数据库这条路上少走几个来回。

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

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

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

立即咨询