数据库
第一章绪论
四个基本概念
- 数据(Data):数据库存储的基本对象,是描述事物的符号记录,包括文本、图形等多种类型,且与其语义不可分割。
- 数据库(DB):长期存储在计算机内、有组织、可共享的大量数据集合,具有结构化、低冗余、高独立、易扩展的特征。
- 数据库管理系统(DBMS):位于用户与操作系统间的基础软件,能实现数据定义、组织存储、操纵、事务管理及维护等功能。
- 数据库系统(DBS):引入数据库后的计算机系统,由数据库、数据库管理系统、应用系统、数据库管理员组成。
数据模型
-
概念模型(E-R 模型)
- 信息世界基本概念:包含实体(可区分的事物)、属性(实体特性)、码(唯一标识实体的属性集)、联系(实体内部及之间的关联)等。
- 联系类型:两个实体型间有 1:1、1:n、m:n 联系;多个实体型及单个实体型内部也存在不同联系。
- E-R 图表示:实体型用矩形、属性用椭圆形、联系用菱形,通过无向边连接,标注联系类型,联系也可拥有属性。
-
逻辑模型
模型类型 数据结构 优缺点 典型代表 层次模型 树形结构,根节点唯一,其他节点仅一个双亲 优点:结构清晰、查询效率高、完整性好;缺点:多对多表示不自然、插入删除限制多 IBM 的 IMS 网状模型 允许多个节点无双亲,一个节点多个双亲 优点:直接描述现实、存取效率高;缺点:结构复杂、DDL/DML 难用 DBTG 系统(CODASYL) 关系模型 二维表结构,实体及联系均用表表示 优点:基于数学概念、概念单一、存取路径透明、独立性高;缺点:查询效率可能较低、需优化 主流 DBMS(如 MySQL)
数据库结构
- 三级模式结构
- 模式(逻辑模式):描述全体数据的逻辑结构与特征,是公共数据视图,一个数据库仅一个模式,独立于硬件和应用。
- 外模式(用户模式):用户使用的局部数据视图,是模式的子集,一个数据库可多个外模式,用于保证数据安全性。
- 内模式(存储模式):描述数据物理结构与存储方式,如存储结构、索引组织等,一个数据库仅一个内模式。
- 二级映像与数据独立性
- 外模式 / 模式映像:定义局部与全局逻辑结构的对应关系,模式改变时修改该映像,保证逻辑独立性(应用程序无需修改)。
- 模式 / 内模式映像:定义全局逻辑与物理结构的对应关系,存储结构改变时修改该映像,保证物理独立性(应用程序不受影响)。
第二章关系数据库
关系数据结构及形式化定义
基本概念
- 域(Domain):一组具有相同数据类型的值的集合。例如:整数域、字符串域等。域中允许的不同取值个数称为域的基数。
- 笛卡尔积(Cartesian Product):给定一组域D₁, D₂, ..., Dₙ,这些域的笛卡尔积为: D₁×D₂×...×Dₙ = {(d₁, d₂, ..., dₙ) | dᵢ∈Dᵢ, i=1,2,...,n} 其中,(d₁, d₂, ..., dₙ) 是笛卡尔积中的元素,称为n元组或简称元组,元素中的每一个值dᵢ叫作一个分量。
- 关系(Relation):笛卡尔积D₁×D₂×...×Dₙ的任意有限子集叫做在域D₁, D₂, ..., Dₙ上的关系,表示为R(D₁, D₂, ..., Dₙ)。R表示关系名,n是关系的目或度。
关系的性质
关系作为一个二维表,具有以下性质:
- 关系的每个属性都是同质的,即每一列中的分量是同一类型的数据,来自同一个域
- 不同的列可出自同一个域,称其中的每一列为一个属性,不同的属性要给予不同的属性名
- 列的顺序无所谓,即列的次序可以任意交换
- 任意两个元组不能完全相同
- 行的顺序无所谓,即行的次序可以任意交换
- 分量必须取原子值,即每一个分量都必须是不可分的数据项
关系相关术语
- 候选码(Candidate Key):若关系中的某一属性组能唯一地标识一个元组,而其子集不能,则称该属性组为候选码
- 主码(Primary Key):从多个候选码中选择一个作为主码
- 主属性(Prime Attribute):候选码的诸属性称为主属性
- 非主属性(Non-prime Attribute):不包含在任何候选码中的属性
关系操作
基本关系操作
关系模型中常用的关系操作包括:
- 查询操作:选择(Selection)、投影(Projection)、连接(Join)、除(Division)、并(Union)、差(Difference)、交(Intersection)、笛卡尔积等
- 选择操作:从关系中选出满足特定条件的元组
- 投影操作:从关系中选出指定的属性列,形成新的关系
- 连接操作:将两个关系中的元组按照某种条件进行配对,形成新的关系
- 除操作:在一个关系中找出那些在另一个关系中存在的元组
- 更新操作:插入(Insert)、删除(Delete)、修改(Update)
关系操作的特点
- 操作对象和结果都是集合(一次一集合的方式)
- 关系操作语言高度非过程化
关系语言的分类
- 关系代数语言:用关系代数表达查询操作
- 关系演算语言:用谓词表达查询操作
- 元组关系演算语言:用元组变量表示关系中的元组,用谓词表示对元组的约束条件
- 域关系演算语言:用域变量表示关系中的属性值,用谓词表示对属性值的约束条件
- SQL语言:结构化查询语言,是关系数据库的标准语言
关系的完整性约束
关系模型的完整性规则是对关系的某种约束条件,目的是保证数据库中数据的正确性和一致性。
实体完整性(Entity Integrity)
- 规则:主码不能为空(NULL)
- 说明:主码用于唯一标识关系中的元组,如果为空则无法实现唯一标识
参照完整性(Referential Integrity)
- 外码定义:设F是基本关系R的一个或一组属性,但不是关系R的码。如果F与基本关系S的主码Ks相对应,则称F是R的外码,基本关系R为参照关系,基本关系S为被参照关系或目标关系。
- 规则:外码的值必须是被参照关系中主码的有效值或者为空值
用户定义的完整性(User-defined Integrity)
- 定义:针对某一具体应用领域的要求而设置的约束条件
- 说明:体现了具体领域中的语义约束,由用户根据实际情况定义
关系代数
关系代数是一种抽象的查询语言,它用对关系的运算来表达查询。
传统的集合运算
- 并(Union):R∪S表示属于R或属于S的元组组成的集合
- 差(Difference):R-S表示属于R但不属于S的元组组成的集合
- 交(Intersection):R∩S表示既属于R又属于S的元组组成的集合
- 笛卡尔积(Cartesian Product):R×S表示R中的元组与S中的元组进行组合
专门的关系运算
- 选择(Selection):σF(R)表示从关系R中选择满足条件F的元组
- 投影(Projection):ΠA(R)表示从关系R中选出若干属性列组成新的关系
- 连接(Join):R∞S表示从R和S的笛卡尔积中选取属性间满足一定条件的元组
- 除(Division):R÷S表示在R和S的公共属性上,R中包含S中所有元组的那些元组
第三章 关系数据库标准语言SQL
SQL(Structured Query Language)是关系数据库的标准语言,也是目前最广泛使用的数据库语言。它集数据定义、数据查询、数据操纵和数据控制功能于一体。
SQL的特点
- 综合统一:集数据定义语言(DDL)、数据操纵语言(DML)、数据控制语言(DCL)于一体。
- 高度非过程化:进行数据操作时,只需提出“做什么”,无需指明“怎么做”。
- 面向集合的操作方式:操作对象和结果都是元组的集合。
- 以同一种语法结构提供多种使用方式:既可以作为独立的语言交互式使用,也可以嵌入到高级语言(如 C++、Java)程序中使用。
数据定义(DDL)
用于定义和管理数据库对象,如表、视图、索引等。
- 模式(Schema)的定义与删除
CREATE SCHEMA <模式名> AUTHORIZATION <用户名>;DROP SCHEMA <模式名> <CASCADE|RESTRICT>;(CASCADE 表示级联删除,RESTRICT 表示若该模式下有对象则拒绝删除)
-
基本表(Table)的定义、修改与删除
- 创建表:
CREATE TABLE <表名> (<列名> <数据类型> [列级完整性约束], ... [表级完整性约束]);- 常用数据类型:
INT,SMALLINT,DECIMAL(p,d),CHAR(n),VARCHAR(n),DATE,TIME等。 - 完整性约束:
PRIMARY KEY,FOREIGN KEY,UNIQUE,NOT NULL,CHECK。 -
示例:创建一个学生表(Student)。
CREATE TABLE Student ( Sno CHAR(9) PRIMARY KEY, Sname CHAR(20) UNIQUE, Ssex CHAR(2), Sage SMALLINT, Sdept CHAR(20) );
- 常用数据类型:
- 修改表:
ALTER TABLE <表名> [ADD <新列名> <数据类型> [完整性约束]] | [DROP <列名>] | [MODIFY <列名> <新数据类型>];- 示例:向Student表增加“入学时间”列。
ALTER TABLE Student ADD S_entrance DATE;
- 示例:向Student表增加“入学时间”列。
- 删除表:
DROP TABLE <表名> <CASCADE|RESTRICT>;-
示例:删除Student表。
DROP TABLE Student;
-
- 创建表:
- 索引(Index)的建立与删除
- 建立索引:
CREATE [UNIQUE] [CLUSTER] INDEX <索引名> ON <表名>(<列名> [ASC|DESC], ...);(UNIQUE: 唯一索引, CLUSTER: 聚簇索引)-
示例:在Student表的Sname列上建立一个唯一索引。
- 删除索引:CREATE UNIQUE INDEX Stusname ON Student(Sname);DROP INDEX <索引名>;- 示例:删除Stusname索引。DROP INDEX Stusname;
-
- 建立索引:
数据查询(DQL)
数据查询是 SQL 的核心功能,通过 SELECT 语句实现。
-
单表查询
SELECT [ALL|DISTINCT] <目标列表达式> FROM <表名> [WHERE <条件表达式>] [GROUP BY <列名1> [HAVING <条件表达式>]] [ORDER BY <列名2> [ASC|DESC]];DISTINCT:去除结果中的重复行。WHERE:指定查询条件。GROUP BY:对结果按指定列进行分组,通常与聚集函数(COUNT,SUM,AVG,MAX,MIN)一起使用。HAVING:对分组后的结果进行筛选。ORDER BY:对最终结果进行排序。-
示例:查询计算机科学系(CS)全体学生的姓名和年龄,并按年龄降序排列。
SELECT Sname, Sage FROM Student WHERE Sdept = 'CS' ORDER BY Sage DESC;
-
示例:查询每个系的学生人数。
SELECT Sdept, COUNT(*) AS TotalStudents FROM Student GROUP BY Sdept;
-
连接查询
- 内连接(INNER JOIN):返回两个表中联结字段相等的行。
FROM <表1> INNER JOIN <表2> ON <连接条件>-
示例:查询每个学生及其选修课程的情况。
SELECT Student.Sno, Sname, Cno, Grade FROM Student INNER JOIN SC ON Student.Sno = SC.Sno;
-
- 外连接(OUTER JOIN):
LEFT JOIN:返回左表的所有行,即使右表中没有匹配。RIGHT JOIN:返回右表的所有行,即使左表中没有匹配。FULL JOIN:返回左右表中的所有行。
- 内连接(INNER JOIN):返回两个表中联结字段相等的行。
-
嵌套查询(子查询)
- 将一个
SELECT语句嵌套在另一个SELECT,INSERT,UPDATE,DELETE语句的WHERE子句或其他位置中。 - 带有
IN的子查询:判断某个值是否在子查询返回的结果集中。-
示例:查询与“刘晨”在同一个系学习的学生。
SELECT Sno, Sname, Sdept FROM Student WHERE Sdept IN ( SELECT Sdept FROM Student WHERE Sname = '刘晨' );
-
- 带有比较运算符的子查询:将主查询的值与子查询返回的单一值进行比较。
- 带有
ANY或ALL的子查询:与比较运算符结合使用,>ANY表示大于子查询结果中的某个值,>ALL表示大于所有值。 - 带有
EXISTS的子查询:判断子查询是否返回任何行。-
示例:查询选修了1号课程的学生姓名。
SELECT Sname FROM Student WHERE EXISTS ( SELECT * FROM SC WHERE Sno = Student.Sno AND Cno = '1' );
-
- 将一个
- 集合查询
UNION:合并两个查询的结果,并自动去除重复行。UNION ALL:合并两个查询的结果,保留所有行(包括重复行)。INTERSECT:返回两个查询结果的交集。EXCEPT:返回在第一个查询结果中但不在第二个查询结果中的行。-
示例:查询计算机系(CS)的学生及年龄不大于19岁的学生。
SELECT Sno, Sname FROM Student WHERE Sdept = 'CS' UNION SELECT Sno, Sname FROM Student WHERE Sage <= 19;
数据更新(DML)
用于操纵数据库中的数据。
-
插入数据(INSERT)
INSERT INTO <表名> [(<列名1>, ...)] VALUES (<值1>, ...);-
示例:向Student表插入一条新记录。
INSERT INTO Student (Sno, Sname, Ssex, Sage, Sdept) VALUES ('201215128', '陈冬', '男', 18, 'IS');
-
INSERT INTO <表名> [(<列名1>, ...)] <子查询>;
- 修改数据(UPDATE)
UPDATE <表名> SET <列名1>=<表达式1>, ... [WHERE <条件>];-
示例:将所有学生的年龄增加1岁。
UPDATE Student SET Sage = Sage + 1;
-
- 删除数据(DELETE)
DELETE FROM <表名> [WHERE <条件>];-
示例:删除学号为“201215128”的学生记录。
DELETE FROM Student WHERE Sno = '201215128';
-
视图(View)
视图是从一个或多个基本表导出的虚拟表,其内容由查询定义。
- 优点:简化用户操作、使用户能以多种角度看待同一数据、对重构数据库提供了一定程度的逻辑独立性、能够对机密数据提供安全保护。
- 创建视图:
CREATE VIEW <视图名> [(<列名1>, ...)] AS <子查询> [WITH CHECK OPTION];(WITH CHECK OPTION表示对视图的更新操作要满足其定义中的条件)-
示例:创建一个信息系(IS)学生的视图。
CREATE VIEW IS_Student AS SELECT Sno, Sname, Sage FROM Student WHERE Sdept = 'IS' WITH CHECK OPTION;
-
- 删除视图:
DROP VIEW <视图名> [CASCADE]; - 查询视图:与查询基本表类似。
- 更新视图:对视图的更新操作最终会转换为对基本表的更新。但并非所有视图都是可更新的(例如,包含聚集函数、
GROUP BY、DISTINCT等的视图)。
数据控制(DCL)
用于授予或收回用户对数据的访问权限。
- 授权(GRANT)
GRANT <权限1>, ... ON <对象类型> <对象名> TO <用户1>, ... [WITH GRANT OPTION];<权限>包括SELECT,INSERT,UPDATE,DELETE,ALL PRIVILEGES等。WITH GRANT OPTION:允许获得权限的用户将此权限再授予其他用户。-
示例:授予用户U1对Student表的查询权限。
GRANT SELECT ON TABLE Student TO U1;
- 收回权限(REVOKE)
REVOKE <权限1>, ... ON <对象类型> <对象名> FROM <用户1>, ... [CASCADE|RESTRICT];CASCADE:级联收回。如果用户A的权限被收回,那么所有由A授予的权限也将被收回。-
示例:从用户U1处收回对Student表的查询权限。
REVOKE SELECT ON TABLE Student FROM U1;
第四章数据库的安全性
数据库安全性概述
- 数据库的不安全因素主要包括:
- 非授权用户对数据库的恶意存取和破坏:黑客或犯罪分子通过获取用户名和口令,假冒合法用户偷取、修改甚至破坏数据。DBMS 通过用户身份鉴别、存取控制、视图等技术应对。
- 数据库中重要或敏感的数据被泄露:黑客等盗窃重要数据,导致机密信息暴露。DBMS 采用强制存取控制、数据加密存储与传输、审计日志分析等技术防范。
- 安全环境的脆弱性:数据库安全性与计算机硬件、操作系统、网络系统的安全性紧密相关。
- 数据库的安全标准:
- TCSEC/TDI
- D级 最小保护,一切不符合更高标准的系统均归为此类
- C级 分为C1和C2,强调对用户的区分和存取控制
- B级 分为B1、B2和B3,强调对数据的保护和系统的完整性
- A级 最高级别,强调形式化的设计和验证
- CC
- 核心:提出国际公认的信息技术安全性表述结构,将信息产品的安全要求分为安全功能要求和安全保证要求。
- TCSEC/TDI
数据库安全性控制
-
数据库安全性控制遵循“层层过滤”原则,主要包括以下三个环节:
- 身份鉴别:通过用户名、密码、生物识别等方式验证用户身份,确保只有合法用户能够访问数据库系统。
- 权限检查:对已鉴别用户的操作请求,先进行自主存取控制(DAC)权限校验,必要时再进行强制存取控制(MAC)校验,以满足高安全级别场景的需求。
- 行为监控:对用户操作进行实时审计和日志记录,结合推理控制技术防止间接数据泄露,实现全流程安全闭环。
-
用户身份鉴别:最外层安全防护
- 静态口令鉴别:用户自行设置固定口令(如密码),操作简单但安全性较低,易被破解。
- 动态口令鉴别:口令实时生成、一次一密(如短信验证码、动态令牌),安全性高于静态口令。
- 生物特征鉴别:通过指纹、虹膜、掌纹等唯一生物特征验证,安全性极高,适用于高敏感场景。
- 智能卡鉴别:借助内置加密芯片的硬件设备(如 U 盾),需物理介质配合,防复制能力强。
-
存取控制:核心权限管理机制
自主存取控制(DAC):用户自主管理自己的数据访问权限,灵活性高,但安全性较低。强制存取控制(MAC):系统根据安全策略强制限制用户访问权限,安全性高,但灵活性差。
- 自主存取控制(DAC)实现:SQL 的 GRANT 与 REVOKE
-- 授予权限(GRANT):将指定数据对象的操作权限给用户,可允许转授。 GRANT SELECT, INSERT ON TABLE Student TO U1 WITH GRANT OPTION; -- 收回权限(REVOKE):撤销已授予的权限,若权限已转授需级联收回(CASCADE)。 REVOKE INSERT ON TABLE Student FROM U1 CASCADE -
强制存取控制(MAC)实现:敏感度标记与规则
- 敏感度标记:为主体(用户 / 进程)和客体(表 / 视图)分配密级,从高到低为 “绝密(TS)> 机密(S)> 可信(C)> 公开(P)”。
- 访问控制规则:
- 读规则:主体许可证级别 ≥ 客体密级(如 “机密” 用户可读 “机密”“可信”“公开” 数据);
- 写规则:主体许可证级别 ≤ 客体密级(如 “可信” 用户可写 “可信”“公开” 数据,防止高权限用户把高敏感信息写入低敏感数据中,导致数据泄露)。
- 自主存取控制(DAC)实现:SQL 的 GRANT 与 REVOKE
视图机制
视图机制是数据库安全性保护的重要手段,核心是通过隐藏敏感数据、配合授权机制,实现对特定用户的数据访问控制。
- 数据隐藏:仅向用户展示其有权访问的部分数据,将无需知晓的敏感信息(如其他部门数据、隐私字段)屏蔽。
- 权限适配:配合 GRANT/REVOKE 授权语句,间接实现 “基于数据内容的权限控制”,让权限管理更精准。
- 操作约束:通过WITH CHECK OPTION子句,限制用户对视图的增删改操作,确保修改后的数据仍符合视图定义条件(如仅允许修改某专业学生信息)。
审计
审计是数据库安全性的 “事后监控” 手段,通过记录用户对数据库的所有操作并形成审计日志,帮助追溯非法行为,是C2 级以上安全标准的必选功能。
- 追溯责任:当发生数据泄露、篡改等安全事件时,通过审计日志定位非法操作的执行人与具体行为。
- 监控合规:确保用户操作符合安全策略,例如监控敏感表的访问频率、权限变更记录。
- 风险预警:通过分析审计日志,发现异常操作模式(如非工作时间高频访问敏感数据),提前防范风险。
审计的实现:
-- 启用审计功能(具体语法视 DBMS 而定)
SET AUDIT_TRAIL TO ON;
-- 配置审计策略:记录对 Student 表的所有 SELECT 操作
AUDIT SELECT ON Student BY ACCESS;
-- 取消审计策略
NOAUDIT ALTER, UPDATE ON SC;
数据加密
- 存储加密:对数据库文件(如数据文件、日志文件)进行加密,加密操作由操作系统或存储系统完成
- 透明存储加密
- 特点:内核级加密,对用户和应用程序完全透明,无需修改代码。
- 流程:数据写入磁盘时自动加密,授权用户读取时自动解密。
- 操作方式:创建表时直接指定需加密的字段,例如在CREATE TABLE语句中添加加密属性。
- 优势:性能较好、安全性高,不影响现有业务逻辑。
- 非透明存储加密
- 特点:通过自定义加密函数实现,需用户手动调用加密 / 解密接口。
- 适用场景:需对特定数据(如核心密码、敏感证件号)进行个性化加密的场景。
- 透明存储加密
- 传输加密:对数据库客户端与服务器之间传输的数据(如 SQL 语句、查询结果)加密,基于 SSL/TLS 协议实现
- 链路加密:ssl/tls 协议加密传输通道,防止中间人攻击和数据窃听。
- 端到端加密:客户端加密数据后发送,服务器端解密处理,确保数据在传输过程中始终处于加密状态。
加密实现方式
- 对称加密:使用单一密钥进行加密和解密,速度快,适用于大数据量加密,但密钥管理复杂。
- AES(高级加密标准):广泛使用的对称加密算法,安全性高,效率好。
- DES(数据加密标准):较早的对称加密算法,现已被认为安全性不足。
- 非对称加密:使用公钥和私钥对进行加密和解密,安全性高,适用于密钥交换和数字签名,但加密速度较慢。
- RSA:常用的非对称加密算法,适用于数据加密和数字签名。
- ECC(椭圆曲线加密):提供相同安全级别下更短密钥长度的非对称加密算法。
第五章数据库的完整性
实体完整性
- 实体完整性是指关系数据库中每个实体(表)都必须有一个唯一标识符(主键),并且主键的值不能为NULL。实体完整性确保了每个实体的唯一性和有效性。
- 实体完整性的检查与违约处理
- 检查:在插入或更新数据时,数据库系统会自动检查主键约束,确保主键的唯一性和非空性。
- 违约处理:如果违反实体完整性约束,数据库系统会拒绝该操作,并返回错误信息。
- 实体完整性的作用
- 确保数据的唯一性:通过主键约束,确保每条记录在表中都是唯一的,避免数据重复。
- 保证数据有效性:主码非空的要求,避免出现 “无学号的学生”“无课程号的选课记录” 这类无效数据,维护数据库语义正确性。
参照完整性
- 参照完整性是指关系数据库中外键约束的有效性,确保一个表中的外键值必须在另一个表的主键中存在。参照完整性维护了表与表之间的关系,避免了孤立数据的出现。
- 参照完整性检查场景
- 参照表(如 SC)插入新元组,外码值(如 Sno)在被参照表(如 Student)中无匹配主码值。
- 参照表(如 SC)修改外码值(如 Cno),修改后的值在被参照表(如 Course)中无匹配主码值。
- 被参照表(如 Student)删除元组,导致参照表(如 SC)中部分元组的外码值(如 Sno)失去匹配主码值。
- 被参照表(如 Course)修改主码值(如 Cno),导致参照表(如 SC)中部分元组的外码值(如 Cno)失去匹配主码值。
- 违约处理
- 拒绝执行
- 联级处理:通过级联操作(如 CASCADE)自动更新或删除相关联的元组,维护数据一致性。
- 设置为空值
用户定义完整性
- 用户定义的完整性是:针对某一具体应用的数据必须满足的语义要求
- 属性上的约束:
- 非空约束(NOT NULL):确保某个属性在每个元组中都有值。
- 唯一约束(UNIQUE):确保某个属性在表中每个元组的值都是唯一的。
- 检查约束(CHECK):检查列值是否满足一个条件表达式。
- 属性上约束的检查和违约处理
- 属性如果不满足则操作被拒绝执行
- 元组上的约束:
- 元组级的限制可以设置不同属性之间的取值的相互约束
- 实现:
-- 在CREATE TABLE语句中可以用CHECK短语定义元组上的约束,即元组级的限制 CREATE TABLE Student ( Sno INT NOT NULL, Sname VARCHAR(100) NOT NULL, Sage INT CHECK (Sage > 0), PRIMARY KEY (Sno), CHECK (Sname <> '' AND Sage > 0) );
- 元组上的约束的检查和违约处理
- 插入元组或修改属性的值时,如果不满足则操作被拒绝执行
完整性约束子句
- 格式:
CONSTRAINT <完整性约束名> <完整性约束> - 修改:使用ALTER TABLE语句修改表中的完整性约束
ALTER TABLE Student ADD CONSTRAINT chk_Sname CHECK (Sname <> ''), DROP CONSTRAINT chk_Sage;
触发器
触发器(Trigger)是一种特殊的存储过程,它在特定事件发生时自动执行。触发器通常用于实现复杂的业务逻辑、数据验证和审计等功能。
- 语法
-- 创建触发器 CREATE TRIGGER <触发器名> {BEFORE | AFTER} <触发事件> ON <表名> REFERENCING NEW|OLD AS <变量> FOR EACH {ROW | STATEMENT} [WHEN <触发条件>] <触发动作体> -- 删除触发器 DROP TRIGGER <触发器名> ON <表名> - 类型:
- 行级触发器(FOR EACH ROW):操作影响多少行,动作体就执行多少次,可通过 NEW(新值)、OLD(旧值)引用行数。
- 语句级触发器(FOR EACH STATEMENT):无论操作影响多少行,动作体仅执行一次,无法引用 NEW/OLD。
- 执行顺序:
- 执行该表上的BEFORE触发器
- 激活触发器的SQL语句
- 执行该表上的AFTER触发器
第六章关系数据理论
问题实例
以STUDENT(Sno, School, Mname, Cno, Grade)为例,存在四大问题:
- 数据冗余:院长姓名(Mname)随学院学生选课记录重复存储。
- 更新异常:更换学院院长需修改该学院所有学生的选课记录。
- 插入异常:新成立学院无学生时,无法存储学院和院长信息。
- 删除异常:删除某学院所有学生记录时,会连带删除学院和院长信息。
函数依赖
- 定义:若关系中任意两元组的X属性值相等,则Y属性值必相等,记为X→Y,X为决定因素,Y为被决定因素。
- 完全函数依赖:Y对X完全函数依赖,则Y对X依赖且对X的任何真子集都不依赖。
- 部分函数依赖:Y对X部分函数依赖,则Y对X依赖但对X的某个真子集也依赖。
- 传递函数依赖:若X→Y且Y→Z,则X→Z。
- 函数依赖的推导规则(Armstrong公理):
- 自反律(Reflexivity):若Y⊆X,则X→Y。
- 增强律(Augmentation):若X→Y,则XZ→YZ。
- 传递律(Transitivity):若X→Y且Y→Z,则X→Z。
码的定义
- 超码(Super Key):能唯一标识关系中元组的属性集。
- 主码(Primary Key):从超码中选取的最小属性集。
- 候选码(Candidate Key):关系中所有最小超码的集合。
范式及其定义
| 范式名称 | 定义 | 解决的问题 | 仍可能存在的问题 |
|---|---|---|---|
| 第一范式(1NF) | 所有属性的值都是原子值,不可再分 | 消除非原子属性,避免属性值不可分 | 存在数据冗余、更新/插入/删除异常 |
| 第二范式(2NF) | 满足1NF,且每个非主属性完全依赖于主码 | 消除部分函数依赖,减少冗余 | 仍可能有传递依赖,导致冗余和异常 |
| 第三范式(3NF) | 满足2NF,且每个非主属性不传递依赖于主码 | 消除传递函数依赖,进一步减少冗余 | 某些语义依赖未处理(如候选码间依赖) |
| 博茨-科得范式(BCNF) | 满足3NF,且所有决定因素都是候选码 | 消除所有非平凡依赖异常 | 某些业务约束无法表达(如多值依赖) |
| 第四范式(4NF) | 满足BCNF,且无多值依赖 | 消除多值依赖,避免重复组合 | 仍可能有连接依赖问题 |
保持依赖的模式分解
- 定义:将一个关系模式R分解为多个子模式R₁, R₂, ..., Rₙ,使得每个子模式都满足某个范式,并且通过自然连接可以无损地重建原始关系R,同时保持所有函数依赖。
- 无损连接分解:分解后通过自然连接能完全恢复原始关系
- 依赖保持分解:分解后所有原始关系的函数依赖都能在子模式中得到表达
- 算法(合成法):
- 根据函数依赖集F,构造每个函数依赖X→Y对应的关系模式R = XY。
- 若没有包含候选码的关系模式,则添加一个包含候选码的关系模式。
- 消除冗余的关系模式。
第七章数据库设计
数据库设计是指根据用户需求,设计和构建数据库及其应用系统的过程。它是一个综合性的工程,涉及计算机基础、程序设计、方法学、软件工程等多个领域。
数据库设计的基本步骤
数据库设计通常分为以下几个阶段:
| 阶段 | 主要任务 | 输入 | 输出 |
|---|---|---|---|
| 需求分析 | 调查和分析用户的数据需求、处理需求、安全性和完整性要求 | 用户需求调查、业务规则 | 数据流图、数据字典、需求规格说明书 |
| 概念结构设计 | 设计数据库的概念模型,通常用E-R图表示 | 需求分析结果 | E-R图、概念模型文档 |
| 逻辑结构设计 | 将概念模型转换为特定DBMS支持的数据模型(如关系模型) | E-R图、DBMS特性 | 数据库逻辑结构、数据表结构 |
| 物理结构设计 | 设计数据库的物理存储结构、索引、存储分配等 | 逻辑结构、DBMS特性、硬件特性 | 物理存储方案、索引设计 |
| 数据库实施 | 根据设计结果创建数据库,编写程序,装入数据 | 物理设计结果 | 数据库实例、应用程序 |
| 数据库运行和维护 | 数据库系统的运行、监控、调整和优化 | 数据库系统 | 运行日志、性能报告 |
需求分析
需求分析是数据库设计的第一步,也是最困难的一步。其主要目标是准确理解用户的需求。
需求分析的内容
- 信息需求:用户需要从数据库中获得什么信息,这些信息的性质、格式和限制。
- 处理需求:用户需要对数据执行什么操作,如查询、插入、更新、删除等。
- 安全性和完整性需求:数据的访问权限、数据约束条件等。
需求分析的方法
- 详细调查用户业务活动和数据流程
- 了解组织机构情况、各部门的输入与输出要求
- 明确新系统的边界
- 收集并分析基础数据
- 确定用户对新系统的各种要求
需求分析的成果
- 数据流图(DFD):描述数据的流动过程

- 数据字典:描述数据库中数据的定义
- 需求规格说明书:全面描述用户的需求
概念结构设计
概念结构设计是将需求分析的结果抽象为独立于具体DBMS的概念模型(E-R模型)。
概念结构设计的重要性
- 真实性:充分反映现实世界,包括实体及其之间的各种联系
- 易理解性:便于用户理解与沟通,是数据库设计者与用户交流的工具
- 易修改性:易于维护与修改
- 易转换性:易于转换为关系、网状、层次等各种数据模型
E-R模型的基本要素
-
实体(Entity):客观存在并可相互区别的事物
- 如:学生、课程、教师
- 同型实体的集合称为实体集
-
属性(Attribute):实体所具有的某一特性
- 简单属性:不可再分的属性,如学号、姓名、年龄
- 复合属性:可以再分的属性,如地址(省、市、区)
- 单值属性:每个实体只有一个值,如学号、姓名
- 多值属性:每个实体可以有多个值,如学生可能有多个电话号码
- 派生属性:可由其他属性计算得到,如年龄可以由出生日期计算
-
码(Key):唯一标识实体的属性集
- 候选码:能够唯一标识实体的属性或属性组
- 主码:从候选码中选择一个作为主码
- 实体必须至少有一个候选码
-
联系(Relationship):实体内部或实体之间的关系
- 实体内部的联系:同一实体集内部不同实体间的联系
- 实体之间的联系:不同实体集之间的关联
联系的分类
-
一对一联系(1:1)
- 定义:实体集A中的每个实体至多与实体集B中的一个实体有联系,反之亦然
- 示例:一个系只有一个系主任,一个系主任只能管理一个系
-
一对多联系(1:n)
- 定义:实体集A中的每个实体可以与实体集B中的任意多个实体有联系,但实体集B中的每个实体至多与实体集A中的一个实体有联系
- 示例:一个系有多个学生,但一个学生只能属于一个系
-
多对多联系(m:n)
- 定义:实体集A中的每个实体可以与实体集B中的任意多个实体有联系,反之亦然
- 示例:一个学生可以选择多门课程,一门课程可以被多个学生选择
多个实体型之间的联系
- 一元联系:同一实体集内部的实体之间的联系
- 如:员工与员工之间的管理关系(一个员工管理多个员工)
- 二元联系:两个实体集之间的联系
- 多元联系:三个或更多实体集之间的联系
- 如:供应商(S)供应(SP)零件(P)给项目(J),这是一个三元联系
E-R图的表示方法
基本符号:
- 矩形:表示实体型
- 椭圆形:表示属性
- 菱形:表示联系
- 无向边:连接实体型与属性、联系与实体型
- 下划线:表示主码
E-R图设计的步骤
-
确定实体及其属性
- 从需求分析中识别主要实体
- 为每个实体确定必要属性
- 确定每个实体的主码
-
确定实体间的联系
- 分析实体间的关系
- 确定联系的类型(1:1、1:n、m:n)
- 为联系分配属性(如果需要)
-
识别实体的子类型(可选)
- 使用ISA("is a")联系表示实体间的层次关系
- 如:学生可以分为本科生和研究生
-
合并局部E-R图,消除冲突
- 属性冲突:同一属性的定义在不同应用中不一致
- 命名冲突:同名异义或异名同义
- 结构冲突:同一对象在不同应用中抽象为不同的实体
逻辑结构设计
逻辑结构设计的任务是将概念模型转换为特定的数据模型(如关系模型),并考虑具体的DBMS的特点。
E-R图向关系模型的转换规则
1. 实体型的转换
- 将实体型转换为一个关系模式
- 实体的属性转换为关系的属性
- 实体的主码转换为关系的主码
示例:
Student(Sno, Sname, Ssex, Sage, Sdept)
2. 联系的转换
二元联系的转换:
| 联系类型 | 转换规则 | 示例 |
|---|---|---|
| 1:1联系 | 联系可以转换为一个独立的关系模式,或者与任意一端对应的关系模式合并 | 若系主任与系是1:1关系,可以: 1. 创建独立关系:DeptDirector(DeptCode, DirectorName) 2. 或者合并到Dept:Dept(DeptCode, DeptName, DirectorName) |
| 1:n联系 | 联系转换为一个独立的关系模式,或者与n端对应的关系模式合并 | 学生与系是1:n关系,可以: 1. 创建独立关系:BelongTo(Sno, DeptCode) 2. 或者合并到Student:Student(Sno, Sname, DeptCode) |
| m:n联系 | 联系必须转换为一个独立的关系模式 | 学生与课程是m:n关系: SC(Sno, Cno, Grade) 主码为(Sno, Cno) |
示例:学生选课系统
E-R图中的实体和联系: - Student(Sno, Sname, Ssex, Sage, Sdept) - Course(Cno, Cname, Ccredit) - SC(Sno, Cno, Grade)
转换后的关系模式:
CREATE TABLE Student (
Sno CHAR(9) PRIMARY KEY,
Sname VARCHAR(20),
Ssex CHAR(2),
Sage SMALLINT,
Sdept VARCHAR(20)
);
CREATE TABLE Course (
Cno CHAR(4) PRIMARY KEY,
Cname VARCHAR(40),
Ccredit SMALLINT
);
CREATE TABLE SC (
Sno CHAR(9),
Cno CHAR(4),
Grade SMALLINT,
PRIMARY KEY (Sno, Cno),
FOREIGN KEY (Sno) REFERENCES Student(Sno),
FOREIGN KEY (Cno) REFERENCES Course(Cno)
);
联系的属性处理:
- 1:1联系:联系的属性可以放到任意一端的实体对应的关系模式中
- 1:n联系:联系的属性必须放到n端对应的关系模式中
- m:n联系:联系的属性必须放到独立的关系模式中
3. 多个实体型之间的联系(多元联系)
- 多元联系转换为一个独立的关系模式
- 关系模式的属性包括与该联系相连的各实体的主码及联系本身的属性
- 关系模式的主码为各实体的主码的组合
示例:供应商供应零件给项目
三元联系 SPJ:
Supplier(Sno, Sname, City)
Part(Pno, Pname, Color)
Project(Jno, Jname)
SPJ(Sno, Pno, Jno, Quantity)
SPJ的主码为(Sno, Pno, Jno),包含三个实体主码的组合。
4. 一元联系的转换
1:n联系:
Employee(Eno, Ename, Job, Mgr)
m:n联系:
Student(Sno, Sname, ...)
Relationship(Sno1, Sno2, RelType)
逻辑结构的优化
数据模型的优化
- 规范化:根据范式理论,对关系模式进行分析和改进
- 消除冗余:删除不必要的重复数据
- 提高查询效率:必要时可以允许一定的冗余以提高查询性能
模式调整
- 合并:如果两个关系的使用频率都很高,且经常进行连接操作,可以考虑合并
- 分解:如果需要经常查询关系中部分属性的数据,可以考虑垂直分解
- 添加冗余:在某些情况下,为了提高查询效率,可以允许一定的数据冗余
物理结构设计
物理结构设计为给定的逻辑数据模型选取一个最适合应用环境的物理结构(存储结构和存取方法)。
物理结构设计的内容
- 存储结构的选择:堆文件、哈希文件、索引文件等
- 存取方法的选择:为关系、属性选择合适的索引
- 存储分配:确定数据的存储位置
- 系统配置:调整DBMS的参数
索引的选择
- 主索引:每个主文件仅一个
- 唯一索引:用于实现唯一性约束
- 聚簇索引:改变数据存储顺序以提高查询效率
- 辅助索引:每个文件可以有多个
数据库实施
数据库实施包括:
- 建立数据库结构:使用DDL语言创建数据库、表、视图、索引等
- 装载数据:将原始数据装入数据库
- 编写和调试应用程序:开发和测试应用程序
- 数据库试运行:对系统进行功能测试和性能测试
数据库运行和维护
数据库正式运行后,需要不断地进行调整和优化:
- 数据库的转储和恢复:定期备份和恢复
- 数据库的安全性、完整性控制:监控和调整安全策略
- 数据库性能的监督、分析和改进:收集统计数据,分析性能瓶颈
- 数据库的重组织与重构造:优化存储结构,改进数据库结构
第八章数据库编程
概述
sql的问题
基础sql语句存在的问题:
- 无法表达递归等复杂操作——例如间接先修课的查询
- 无法对数据进行复杂操作——查询一周内将过生日的同学
- 无法自主设计业务处理逻辑——计算学生平均学分绩点
- 无法进行交互式操作——教学评价与反馈
通过高级语言实现复杂操作
为了解决 SQL 的局限性,通常采用以下三种方式将数据库功能融入高级语言:
- 通过动态链接库调用的方式
关系数据库管理系统的功能被包装成一个子程序,由应用程序通过动态链接库调用来获得数据管理的功能。
- 基于嵌入式 SQL 的方式
将 SQL 嵌入到高级语言中混合编程,SQL 语句负责操纵数据库,高级语言语句负责控制逻辑流程。
- 基于 ODBC/JDBC 的中间件方式
建立了连接不同数据库的一组规范。无论使用什么数据库,都采用同样的一组 API 来访问数据库。
过程化SQL
过程化SQL的块结构
过程化SQL(如 PL/SQL、T-SQL)以"块"为基本执行单元,块内部可声明变量、编写流程控制语句,并可嵌套子块。典型块结构分为三部分:
-
声明部分(DECLARE)
用于定义局部变量、常量、游标、用户自定义异常等。
示例:
DECLARE v_score NUMBER(5,2) := 90; v_name VARCHAR2(20); -
执行部分(BEGIN…END)
包含实际的可执行语句,支持顺序、分支、循环等控制结构。
示例:
BEGIN SQL语句、过程化SQL的流程控制语句 EXCEPTION 处理异常情况 END;
块可以匿名运行,也可封装为存储过程、函数、触发器或包,供应用程序重复调用,从而实现复杂业务逻辑与数据库操作的紧密集成。
变量和常量的定义
变量定义语法:
变量名 数据类型 [NOT NULL] [:= 初始值];
常量定义语法:
常量名 CONSTANT 数据类型 := 值;
复合类型语法:
-- 记录类型
TYPE 类型名 IS RECORD (字段定义);
-- 表类型
TYPE 类型名 IS TABLE OF 数据类型 INDEX BY 索引类型;
流程控制
条件语句:
IF 条件1 THEN
语句1;
ELSIF 条件2 THEN
语句2;
ELSE
语句3;
END IF;
CASE 表达式
WHEN 值1 THEN 语句1;
WHEN 值2 THEN 语句2;
ELSE 语句3;
END CASE;
循环语句:
-- 简单循环
LOOP
语句;
EXIT WHEN 条件;
END LOOP;
-- WHILE循环
WHILE 条件 LOOP
语句;
END LOOP;
-- FOR循环
FOR 变量 IN [REVERSE] 下限..上限 LOOP
语句;
END LOOP;
游标的定义与使用
显式游标:
-- 声明游标
CURSOR 游标名 IS 查询语句;
-- 使用游标
OPEN 游标名;
FETCH 游标名 INTO 变量列表;
CLOSE 游标名;
带参数的游标:
CURSOR 游标名(参数列表) IS 查询语句;
游标属性:
- %FOUND:最近一次FETCH是否成功
- %NOTFOUND:最近一次FETCH是否失败
- %ISOPEN:游标是否打开
- %ROWCOUNT:已获取的行数
存储过程
创建存储过程语法:
CREATE [OR REPLACE] PROCEDURE 过程名(参数列表) [AS|IS]
局部变量声明;
BEGIN
执行语句;
EXCEPTION
异常处理;
END 过程名;
参数模式: - IN:输入参数(默认) - OUT:输出参数 - IN OUT:输入输出参数
存储函数
创建存储函数语法:
CREATE [OR REPLACE] FUNCTION 函数名(参数列表) RETURN 返回类型 [AS|IS]
局部变量声明;
BEGIN
执行语句;
RETURN 返回值;
EXCEPTION
异常处理;
END 函数名;
存储函数与存储过程的区别:
- 函数必须返回值,过程可以不返回
- 函数可在SQL表达式中直接使用,过程不能
- 函数主要用于计算和返回值,过程主要用于执行操作
JDBC 简介
JDBC(Java Database Connectivity)是 Java 提供的标准数据库访问接口,位于 java.sql 与 javax.sql 包中。
通过 JDBC,Java 程序可用统一方式连接各类关系数据库,完成加载驱动、建立连接、发送 SQL、处理结果集及事务控制等操作,实现“一次编写,处处连接”。
第九章数据库恢复技术
事务的基本概念
事务定义:事务是用户定义的一个数据库操作序列,这些操作要么全做,要么全不做,是一个不可分割的工作单位。
ACID特性: - 原子性(Atomicity):事务中的所有操作要么都执行,要么都不执行 - 一致性(Consistency):事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态 - 隔离性(Isolation):一个事务的执行不能被其他事务干扰 - 持久性(Durability):一旦事务提交,其对数据库的修改就是永久性的
事务状态: - 活动状态:事务执行中 - 部分提交:最后一条语句执行后 - 失败:不能正常执行 - 中止:事务回滚 - 提交:成功完成
故障的种类
事务故障: - 逻辑错误:事务执行时发生逻辑错误 - 系统错误:系统进入不良状态,无法继续执行
系统故障: - 硬件故障、软件错误、停电等导致系统停止运行 - 主存内容丢失,外存完好
介质故障: - 磁盘损坏、磁头碰撞、病毒等 - 外存上的数据部分或全部丢失
恢复的实现技术
数据转储: - 静态转储:系统无运行事务时进行 - 动态转储:系统运行中同时进行转储 - 海量转储:转储全部数据库 - 增量转储:只转储上次转储后的更新
登记日志文件: - 日志记录:记录事务对数据库的修改操作 - 日志文件:保存所有日志记录的文件 - 先写日志规则:对数据库的修改必须先写日志
恢复策略
事务故障恢复: - 反向扫描日志文件,查找该事务的更新操作 - 对该事务的更新操作执行逆操作 - 继续反向扫描直至事务开始标记
系统故障恢复: - 正向扫描日志文件,找出已提交和未提交事务 - 对未提交事务进行撤销(UNDO) - 对已提交事务但更新未写入数据库的事务进行重做(REDO)
介质故障恢复: - 重装数据库转储的后备副本 - 重做自转储以来的所有已提交事务
具有检查点的恢复技术
检查点技术: - 定期设置检查点,保存数据库状态 - 检查点记录:包括检查点时刻所有活动事务列表 - 检查点作用:减少恢复时需要扫描的日志量
检查点恢复步骤: 1. 从最近检查点开始正向扫描日志 2. 建立重做队列和撤销队列 3. 对重做队列中的事务执行REDO操作 4. 对撤销队列中的事务执行UNDO操作
第十章并发控制
并发控制概述
并发控制是数据库管理系统中的重要组成部分,主要用于管理多个事务同时访问和修改共享数据时的协调机制。在多用户环境下,如果没有有效的并发控制,可能会导致:
- 丢失更新(Lost Update)——最经典的“写冲突”
场景:事务 A 和事务 B 同时读到同一行数据(例如账户余额 100 元)。- A 把余额改成 90 元并提交;
- B 完全不知道 A 已提交,仍基于最初读到的 100 元计算,再改成 80 元并提交。
结果:A 的修改被 B 的提交彻底覆盖,仿佛 A 从未操作过,银行账目凭空少了 10 元。
关键点:并发写必须加排他锁(X 锁)或采用“乐观锁版本号”机制,否则必出问题。
- 脏读(Dirty Read)——读到别人“草稿”
场景:事务 A 把某数据从 100 改成 90,但尚未提交;此时事务 B 就读到了 90。
后续:如果 A 回滚,数据回到 100,那么 B 刚才拿到的 90 就是“脏东西”。
后果:B 基于脏数据做的任何计算、展示或再写入都会产生错误。
关键点:只有把隔离级别调到 ≥ Read Committed,才能禁止读取未提交数据。 - 不可重复读(Non-repeatable Read)——同一事务里数据“变脸”
场景:事务 A 第一次读某数据得到 100,继续做其他逻辑;期间事务 B 把该数据改成 90 并提交;当 A 再次读取同一数据时,发现变成了 90。
后果:A 的后续逻辑(如校验、累加、对账)因数据变脸而失效。
关键点:隔离级别 ≥ Repeatable Read 会在第一次读时加共享锁或利用 MVCC 快照,保证同一事务多次读取结果一致。 - 幻读(Phantom Read)——记录条数突然“多出几行”
场景:事务 A 按条件“金额 > 0”首次查询得到 5 条记录;此时事务 B 插入一条新记录(金额 = 50)并提交;A 再次按相同条件查询,发现变成了 6 条记录,仿佛出现了“幻影”。
后果:统计、分页、批量更新等操作结果失真,业务逻辑被悄悄篡改。
关键点:只有 Serializable 隔离级别或 InnoDB 的间隙锁(Gap Lock)能把“范围”锁住,彻底杜绝幻影行。
事务的隔离级别
数据库系统提供了四种标准的事务隔离级别,用于控制事务之间的可见性和影响程度:
- 读未提交(Read Uncommitted)
- 最低的隔离级别
- 一个事务可以读取另一个事务尚未提交的数据
- 可能导致脏读、不可重复读和幻读
- 读已提交(Read Committed)
- 一个事务只能读取另一个事务已经提交的数据
- 避免了脏读,但仍可能出现不可重复读和幻读
- 大多数数据库系统的默认隔离级别
- 可重复读(Repeatable Read)
- 保证在同一个事务中多次读取同一数据的结果一致
- 避免了脏读和不可重复读,但仍可能出现幻读
- MySQL的InnoDB引擎的默认隔离级别
- 串行化(Serializable)
- 最高的隔离级别
- 事务完全串行执行,一个接一个
- 避免了所有并发问题,但并发性能最低
封锁
封锁是实现并发控制的基本技术,通过在数据对象上设置锁来控制并发访问。
基本锁类型
- 共享锁(Shared Lock,S锁)
- 也称为读锁
- 允许事务读取数据
- 多个事务可以同时持有同一数据对象的共享锁
- 排他锁与共享锁互斥
- 排他锁(Exclusive Lock,X锁)
- 也称为写锁
- 允许事务读取和修改数据
- 一个数据对象上只能有一个事务持有排他锁
- 排他锁与所有其他锁类型互斥
锁的兼容性矩阵
| 已申请/请求 | S锁 | X锁 |
|---|---|---|
| S锁 | 兼容 | 不兼容 |
| X锁 | 不兼容 | 不兼容 |
封锁协议
封锁协议是一组规则,规定了事务何时申请锁、何时释放锁,以及锁的类型和持续时间。
- 一级封锁协议
- 事务T在修改数据R之前必须先对其加X锁
- 直到事务结束才释放X锁
- 可以防止丢失修改
- 二级封锁协议
- 满足一级封锁协议
- 事务T在读取数据R之前必须先对其加S锁
- 读完后即可释放S锁
- 可以防止丢失修改和读"脏"数据
- 三级封锁协议
- 满足二级封锁协议
- 事务T在读取数据R之前必须先对其加S锁
- 直到事务结束才释放S锁
- 可以防止丢失修改、读"脏"数据和不可重复读
活锁和死锁
活锁
活锁是指事务虽然未被阻塞,但始终无法获得所需锁的情况。例如,多个事务不断请求同一资源,系统总是优先满足其他事务,导致某个事务一直等待。
解决活锁的方法: - 采用先来先服务策略 - 设置等待时间上限,超过后重新排队
死锁
死锁是指两个或多个事务互相等待对方持有的锁,导致所有事务都无法继续执行的情况。
死锁产生的四个必要条件: 1. 互斥条件:资源不能被多个事务同时使用 2. 请求与保持条件:事务已获得部分资源,还在请求其他资源 3. 不可剥夺条件:资源不能被强制性地从持有它的事务中剥夺 4. 循环等待条件:存在事务资源的循环等待链
死锁的处理方法: 1. 死锁预防:破坏死锁产生的四个必要条件之一 2. 死锁避免:在事务申请锁时进行检测,若可能导致死锁则拒绝 3. 死锁检测与解除:定期检测死锁,发现后通过回滚事务解除
并发调度的可串行性
调度
调度是指多个事务的操作序列的执行顺序。如果调度的结果与这些事务按某种串行顺序执行的结果相同,则称该调度是可串行化的。
可串行化调度
可串行化调度是指并发执行的事务操作序列等价于某个串行执行顺序的调度。可串行化调度能够保证数据库的一致性。
冲突可串行化
冲突可串行化是一种特殊的可串行化,通过交换不冲突的操作顺序,可以将调度转换为串行调度。两个操作冲突的条件是: 1. 它们属于不同事务 2. 它们操作同一数据项 3. 至少有一个是写操作
冲突可串行化的判定
可以通过优先图(Precedence Graph)来判断一个调度是否是冲突可串行化的: 1. 为每个事务创建一个节点 2. 如果事务Ti的操作在Tj的操作之前且两者冲突,则从Ti到Tj画一条有向边 3. 如果图中无环,则调度是冲突可串行化的
两段锁协议
两段锁协议(Two-Phase Locking Protocol, 2PL)是一种广泛使用的封锁协议,用于保证调度的可串行性。
协议规则
- 扩展阶段:事务可以申请锁,但不能释放任何锁
- 收缩阶段:事务可以释放锁,但不能申请任何新锁
协议特点
- 严格遵守两段锁协议的事务调度一定是冲突可串行化的
- 但冲突可串行化的调度不一定遵守两段锁协议
- 两段锁协议不能避免死锁
严格两段锁协议
严格两段锁协议是两段锁协议的增强版本,要求事务持有的所有锁必须在事务提交或中止后才能释放。这样可以避免级联回滚问题。
封锁的粒度
封锁粒度是指封锁对象的大小。不同的封锁粒度对并发控制和系统性能有不同的影响。
封锁粒度的类型
-
粗粒度封锁
- 封锁对象较大(如整个数据库、整个表)
- 管理简单,开销小
- 并发度低,容易引起冲突
-
细粒度封锁
- 封锁对象较小(如记录、字段)
- 并发度高,冲突少
- 管理复杂,开销大
-
多粒度封锁
- 同时支持多种封锁粒度
- 根据应用需求动态选择封锁粒度
- 兼顾并发度和系统开销
意向锁
多粒度封锁中引入意向锁来提高效率:
-
意向共享锁(IS锁)
- 表示事务打算在某个数据对象上加共享锁
- 在对表加IS锁后,可以在表的记录上加S锁
-
意向排他锁(IX锁)
- 表示事务打算在某个数据对象上加排他锁
- 在对表加IX锁后,可以在表的记录上加X锁
-
共享意向排他锁(SIX锁)
- 表示事务对整个表加共享锁,同时对某些记录加排他锁
- SIX = S + IX
锁的兼容性矩阵(包含意向锁)
| 已申请/请求 | IS | IX | S | SIX | X |
|---|---|---|---|---|---|
| IS | 兼容 | 兼容 | 兼容 | 兼容 | 不兼容 |
| IX | 兼容 | 兼容 | 不兼容 | 不兼容 | 不兼容 |
| S | 兼容 | 不兼容 | 兼容 | 不兼容 | 不兼容 |
| SIX | 兼容 | 不兼容 | 不兼容 | 不兼容 | 不兼容 |
| X | 不兼容 | 不兼容 | 不兼容 | 不兼容 | 不兼容 |
封锁粒度的选择需要根据具体应用场景权衡并发度和系统开销,通常数据库系统会采用多粒度封锁机制,根据操作特点动态调整封锁粒度。