第 1 课 关系模型与关系代数
对应教材第 2 章。SQL 的理论基础。
关系就是一张二维表,但有三条规范化要求:列同质、列可交换、行不重复。 关系代数用一组运算描述查询,是 SQL 的数学基础。 五种基本运算是并、差、笛卡尔积、选择、投影,其余(交、连接、除)都可由它们导出。
-- 关系代数符号与含义
σ(选择):按条件挑行 π(投影):挑指定的列
∪ 并 − 差 ∩ 交 × 笛卡尔积 ⋈ 连接 ÷ 除
-- 例:查询选修了 2 号课程的学生的姓名
π Sname (σ Cno='2' (SC ⋈ Student))
-- 例:查询选修了全部课程的学生学号(除运算)
π Sno,Cno (SC) ÷ π Cno (Course)
-- 对应的 SQL 写法(EXISTS 表达形式)
SELECT Sno FROM Student
WHERE NOT EXISTS (
SELECT * FROM Course WHERE NOT EXISTS (
SELECT * FROM SC WHERE SC.Sno = Student.Sno AND SC.Cno = Course.Cno));
- 并、差、交要求两个关系的属性个数相同且类型相容;笛卡尔积无此要求。
- 自然连接按同名属性等值连接并去掉重复列;等值连接保留重复列。
- 除运算用于"全部 / 所有"类查询,对应 SQL 中的双层 NOT EXISTS。
- 三类完整性:实体(主码非空不重)、参照(外码取值受限)、用户定义。
课堂练习(4 题)
- 用关系代数表示:查询计算机系(CS)全体学生的学号与姓名。
答:
π Sno,Sname (σ Sdept='CS' (Student)) - 用关系代数表示:查询至少选修了一门课的学生姓名。
答:
π Sname (Student ⋈ π Sno (SC)) - 自然连接与等值连接的结果有何差别? 答:自然连接在等值连接的基础上去掉重复的属性列(同名属性只保留一份)。
- 关系代数的基本运算为什么不包含交、连接、除? 答:因为它们可由五种基本运算导出(如 A∩B = A−(A−B)),引入只是为了表达方便。
第 2 课 安全性与完整性
对应教材第 4、5 章。一个防"非法的人",一个防"不合法的数据"。
安全性关注防止非法用户与非法操作,手段包括身份鉴别、存取控制、视图、审计、加密; 完整性关注数据本身是否正确、有效、相容,手段是各类约束与触发器。 二者目标不同:即使一个用户完全合法,也可能输入违反语义的数据——这正是完整性要管的。
-- 自主存取控制
GRANT SELECT ON TABLE Student TO U1 WITH GRANT OPTION; -- 可再授权
GRANT UPDATE(Sage) ON TABLE Student TO U2; -- 列级权限
REVOKE UPDATE(Sage) ON TABLE Student FROM U2;
CREATE ROLE R1; GRANT SELECT ON TABLE Student TO R1; GRANT R1 TO 王平;
-- 完整性约束
CREATE TABLE SC (
Sno CHAR(9) NOT NULL,
Cno CHAR(4) NOT NULL,
Grade SMALLINT CHECK (Grade BETWEEN 0 AND 100), -- 用户定义完整性
PRIMARY KEY (Sno, Cno), -- 实体完整性
FOREIGN KEY (Sno) REFERENCES Student(Sno) -- 参照完整性
ON DELETE CASCADE ON UPDATE NO ACTION
);
-- 命名约束后便于修改
ALTER TABLE SC DROP CONSTRAINT C1;
- 自主存取控制(DAC)按权限授权;强制存取控制(MAC)按密级标记强制约束。
- 参照完整性违约处理:NO ACTION(拒绝)、CASCADE(级联)、SET NULL(该列须可空)。
- 审计是事后手段,加密是事前手段,视图可用来隐藏数据实现授权。
课堂练习(4 题)
- 简述数据库安全性与完整性的区别。 答:安全性防止非法用户与非法操作,保护数据不被泄露或破坏;完整性保证数据本身正确、有效、相容,防止不合语义的数据进入数据库。
- U1 把权限转授给了 U2,收回 U1 权限后 U2 仍有权限,原因是什么? 答:REVOKE 未写 CASCADE,不会级联收回 U1 转授出去的权限。
- 删除 Student 中某元组时被拒绝,可能的原因是什么? 答:SC 中存在引用该学生的外码,且外码的删除违约策略为 NO ACTION(默认),因此拒绝删除。
- 哪种违约处理要求外码列允许为空? 答:SET NULL(置空值)策略,因为需要把外码列写成 NULL。
第 3 课 范式与模式分解
对应教材第 6 章。判断"表设计得好不好"的标准。
设计不好的关系模式会带来冗余与三类异常(插入、删除、更新)。 规范化通过分解关系模式逐步消除不合适的函数依赖: 1NF(属性不可再分)→ 2NF(消除非主属性对码的部分依赖)→ 3NF(消除传递依赖)→ BCNF(所有决定因素都含码)→ 4NF(消除多值依赖)。 求候选码的标准方法是属性闭包。
-- 例:关系模式 SLC(Sno, Sdept, Sloc, Cno, Grade),语义为一个学生只在一个系 -- 函数依赖:Sno → Sdept,Sdept → Sloc,(Sno,Cno) → Grade -- 码:(Sno, Cno) -- 问题:Sdept 与 Sloc 只依赖于 Sno(部分依赖)→ 不是 2NF,存在冗余与更新异常 -- 分解:SL(Sno, Sdept, Sloc) 与 SC(Sno, Cno, Grade) -- SL 中 Sno → Sdept → Sloc 是传递依赖 → 再分解为 SD(Sno, Sdept) 与 DL(Sdept, Sloc) -- 最后得到三个 3NF 关系:SD(Sno,Sdept)、DL(Sdept,Sloc)、SC(Sno,Cno,Grade)
- 求候选码:先找出只在依赖左部出现的属性(必含于任何码),再求闭包验证。
- 判断范式要逐层检查:先 2NF(是否存在部分依赖),再 3NF(是否存在传递依赖),再 BCNF。
- BCNF ⊂ 3NF:满足 BCNF 一定满足 3NF,反之不成立。
- 模式分解的两个标准:无损连接性与保持函数依赖,二者有时不可兼得。
课堂练习(4 题)
- 关系模式 R(A,B,C),F = {A→B, B→C},求候选码并判断最高范式。 答:A 的闭包为 {A,B,C},候选码为 A。A→B→C 是传递依赖,非主属性 C 传递依赖于码 A,故最高只到 2NF,不属于 3NF。
- 什么叫无损连接分解? 答:分解后的若干关系做自然连接能够完全还原原关系(不多不少),则称该分解具有无损连接性。
- 3NF 与 BCNF 的区别是什么? 答:3NF 允许主属性对码的部分或传递依赖,BCNF 要求每一个决定因素都必须包含码,因此 BCNF 更严格。
- 分解时无法同时做到无损连接与保持函数依赖,应如何选择? 答:通常优先保证无损连接性(否则会丢失或增生信息),保持依赖可退而求其次,必要时用触发器等机制在应用层维护。
第 4 课 E-R 设计与关系模式转换
对应教材第 7 章。从需求到表结构的完整过程。
数据库设计分六个阶段:需求分析 → 概念结构设计(E-R 图)→ 逻辑结构设计(转成关系模式)→ 物理结构设计 → 实施 → 运行维护。 其中最关键的是 E-R 图向关系模式的转换,转换规则按联系的基数(1:1、1:n、m:n)而不同。
-- 转换规则要点 -- ① 一个实体型 → 一个关系模式,实体的属性即关系的属性,实体的码即关系的码 -- ② 1:1 联系:可并入任意一端(在该端加另一端的码),也可单独建关系 -- ③ 1:n 联系:并入 n 端(在 n 端关系中加 1 端的码),若联系有属性则一并加入 -- ④ m:n 联系:必须单独建立一个关系,属性为两端实体的码 + 联系自身的属性,码为两端码的组合 -- ⑤ 三个及以上实体的多元联系:单独建关系,码为各实体码的组合 -- 例:学生与课程是 m:n 联系"选修",带属性"成绩" -- Student(Sno, Sname, ...) Course(Cno, Cname, ...) -- SC(Sno, Cno, Grade) 主码 (Sno, Cno),两个外码分别参照 Student 与 Course
- 概念模型独立于具体 DBMS,逻辑结构设计才与数据模型(关系/层次/网状)相关。
- E-R 图的三要素:实体(矩形)、属性(椭圆)、联系(菱形),联系要标注基数。
- 合并 E-R 图时要解决三类冲突:属性冲突、命名冲突、结构冲突。
- 逻辑设计阶段还要做关系模式优化(通常以 3NF 为目标)。
课堂练习(4 题)
- 为什么 m:n 联系必须单独建立关系模式? 答:一个实体可以对应多个另一端的实体,无法用单一属性表示,必须用独立的关系记录每一对关联,并把两端主码组合作为该关系的码。
- 1:n 联系如何转换?举例说明。 答:并入 n 端。例如"系—学生"为 1:n,可在 Student 中加属性 Sdept(系号)作为外码,联系自身的属性也一并加入。
- 需求分析阶段的主要产物是什么? 答:数据流图与数据字典(数据项、数据结构、数据流、数据存储、处理过程),以及需求说明书。
- 合并分 E-R 图时要消除哪些冲突? 答:属性冲突(类型/取值范围不一致)、命名冲突(同名异义、异名同义)、结构冲突(同一对象在不同应用中抽象不同)。
第 5 课 事务与并发控制
对应教材第 12 章(事务概念见第 11 章)。
多个事务并发执行会产生三类数据不一致:丢失修改、不可重复读、读脏数据。 并发控制的目标是让并发调度的结果等价于某种串行调度(可串行化)。 最常用的机制是封锁:X 锁(写锁、排它)、S 锁(读锁、共享),配合不同级别的封锁协议解决问题。
-- 事务 BEGIN TRANSACTION; SELECT ...; UPDATE ...; COMMIT; -- 提交;出错则 ROLLBACK 回滚 -- 封锁与协议 -- 一级封锁协议:修改前加 X 锁直到事务结束 → 防止丢失修改 -- 二级封锁协议:一级 + 读取前加 S 锁读完即放 → 防止读脏数据 -- 三级封锁协议:一级 + 读取前加 S 锁直到结束 → 防止不可重复读 -- 两段锁协议:加锁阶段与解锁阶段严格分开 → 保证并发调度可串行化 -- 多粒度封锁:意向锁 IS / IX / SIX 提高加锁检查效率
- 事务 ACID:原子性、一致性、隔离性、持久性。
- 可串行化是并发调度正确性的准则;冲突可串行化是其充分条件(判定用优先图是否有环)。
- 两段锁协议保证可串行化,但可能产生死锁;一次封锁法不会死锁但并发度低。
- 活锁用先来先服务避免;死锁用超时法或等待图法检测、撤销事务解除。
课堂练习(4 题)
- 什么是丢失修改?举例说明。 答:两个事务同时读同一数据并各自修改,后提交的覆盖了先提交的结果,导致先前的修改丢失。例如 T1 与 T2 同时读余额 100,分别减 10 与减 20,最终结果取决于谁最后写入,其中一次修改被覆盖。
- 两段锁协议与一次封锁法的区别? 答:两段锁把加锁与解锁分为两个阶段,允许逐步加锁,能保证可串行化但可能死锁;一次封锁法要求一次申请全部锁,不会死锁但降低并发度。
- 如何判断一个调度是冲突可串行化的? 答:构造优先图(冲突操作按先后连边),若图中无环,则为冲突可串行化调度;有环则不是。
- 事务的持久性由什么机制保证? 答:由恢复机制保证——通过日志文件与"先写日志"原则,已提交事务的修改在系统故障后仍可重做(REDO)。
第 6 课 恢复技术
对应教材第 11 章。出故障后如何把数据库恢复到正确状态。
恢复的两大支柱是数据转储(备份副本)与日志文件(记录每次更新)。 核心原则是先写日志:必须先把日志记录写到稳定存储,再写数据库,否则故障后无法判断该重做还是撤销。 恢复时,对未完成事务做 UNDO(撤销),对已提交但未落盘的事务做 REDO(重做)。
-- 日志记录的典型内容 -- 事务开始标记:<Ti BEGIN> -- 更新记录:<Ti, 数据对象, 旧值, 新值> -- 提交标记:<Ti COMMIT> -- 恢复策略 -- 事务故障:反向扫描日志,对该事务的更新执行 UNDO,直到 BEGIN -- 系统故障:正向扫描找已提交事务 → REDO;未完成事务 → UNDO -- 介质故障:装入最近的后备副本 + 重做此后所有已提交事务 -- 检查点技术:定期写检查点记录,恢复时只需处理检查点之后的事务,缩短扫描范围
- 先写日志原则(WAL):先写日志再写数据库,是恢复正确性的前提。
- UNDO 撤销未完成事务,REDO 重做已提交事务,方向不要搞反。
- 检查点只是缩短扫描范围,不能替代日志;数据库镜像用于提高可用性。
- 故障种类:事务内部故障、系统故障、介质故障、计算机病毒。
课堂练习(3 题)
- 为什么必须先写日志再写数据库? 答:若先写数据库后写日志,在两次写入之间发生故障,日志中没有该修改记录,恢复时既无法撤销也无法重做,数据库会处于不一致状态。
- 系统故障恢复时,哪些事务需要 REDO,哪些需要 UNDO? 答:日志中有 COMMIT 记录的事务需要 REDO(重做其修改),只有 BEGIN 没有 COMMIT 的事务需要 UNDO(撤销其修改)。
- 检查点的作用是什么? 答:周期性记录当前活跃事务与脏页信息并强制写盘,恢复时从最近的检查点开始处理,避免扫描整个日志,加快恢复速度。