数据库原理 - 复习(二)
第四章 数据库安全性
数据库的数据保护主要包括数据的安全性和完整性。
4.1 数据库安全性概述
数据库的安全性是指保护数据库以防不合法使用所造成的数据泄露,更改或破坏。
安全性:去银行取钱需要输入密码
完整性:取的钱需要小于等于卡里面的钱
4.1.1 数据库的不安全因素
- 非授权用户对数据库的恶意存取和破坏
- 数据库中重要或敏感的数据被泄露
- 安全环境的脆弱性
4.2 数据库安全性控制
存取控制(AC–Acess Control)
- 自主存取控制方法(DAC):
用户对于不同的数据库对象有不同的存取权限,不同的用户对同一对象也有不同的权限,而且用户还可以将其拥有的存取权限转授给其他用户。非常灵活。主要通过SQL的GRANT语句和REVOKE语句来实现。 - 强制存取控制方法(MAC)
每一个数据库对象被标以一定的密级,每一个用户也被授予某一个级别的许可证。对于任意一个对象,只有具有合法许可证的用户才可以存取。较为严格。
基于角色访问控制(RBAC—Role-Based Acess Control)
数据库的安全性,主要包括身份鉴定、多层存取控制、审计、视图和数据加密等安全技术。


存取控制流程:
- 首先,数据库管理系统对提出SQL访问请求的数据库用户进行身份验证,防止不可信用户使用
- 然后,在SQL处理层进行自主存取控制和强制存取控制,进一步可以进行推理控制
- 还可以对用户访问行为和系统关键操作进行审计,对异常用户行为进行简单入侵检测
4.2.1 用户身份鉴别
用户身份鉴别是数据库管理系统提供的最外层安全保护措施。
每个用户在系统中都有一个用户标识。
每个用户标识都由 用户名(user name) 和**用户标识号(UID) **两部分组成。
静态口令鉴别
- 其实就是输入密码。所以,这种方式虽然简单,但容易被攻击,安全性较低。
动态口令鉴别
- 通过生物特征进行认证。例如指纹,虹膜和掌纹等。安全性较高
智能卡鉴别
- 智能卡是一种不可复制的硬件,内置集成电路的芯片,具有硬件加密功能。(就比如你去银行取钱,需要出示的不仅是银行卡号,还有身份证一样)。
4.2.3 自主存取控制方法
用户权限是由两个要素组成:数据库对象和操作类型。(用户可以在数据库的哪些对象上进行哪些操作)在数据库系统中,定义存取权限称为授权。
在关系数据库系统中,存取控制对象不仅有数据本身(基本表中的数据,属性列上的数据),还有数据库模式(包括数据库、基本表、视图和索引的创建等)。

4.2.4 授权:授予与收回
SQL中使用==GRANT(授予)和REVOKE(收回)==语句向用户授予或收回数据的操作权限。
GRANT语法格式:
GRANT<权限>[,<权限>]...
ON <对象类型><对象名>[,<对象类型><对象名>]...
TO <用户>[,<用户>]...
[WITH GRANT OPTION]
如果添加了WITH GRANT OPTION子句,则获得某种权限的用户还可以把这种权限再授予给其他用户,但是不允许循环授权,即被授予者不能再把权限授予给授权者或祖先。

#把查询Student表的权限授予给用户U1
GRANT SELECT
ON TABLE Student
TO U1;#把对Student和Course表的全部权限授予给用户U2和U3
GRANT ALL PRIVILEGES
ON TABLE Student,Course
TO U2,U3;#把对SC表的查询权限给所有用户
GRANT SELECT
ON TABLE SC
TO PUBLIC;#把查询Student表和修改学生学号的权限给U1
#注意:对属性列授权时必须明确指出相应的属性列名
GRANT SELECT,UPDATE(Sno)
ON TABLE Studnet
TO U1;
REVOKE语法格式:
REVOKE <权限>[,<权限>]...
ON <对象类型><对象名>[,<对象类型><对象名>]...
FROM <用户>[,<用户>]...[CASCADE|RESTRICT];
#把用户U4修改学生学号的权限收回
REVOKE UPDATE(Sno)
ON TABEL Student
FROM U4;#假设U5还将INSERT权限授予给了U6用户,现在把用户U5对SC表的INSERT权限收回
REVOKE INSERT
ON TABLE SC
FROM U5 CASCADE;
#注意:这里使用的是CASCADE,有的数据库管理系统默认为RESTRICT,将自动执行级联删除。
创建数据库模式的权限
CREAT USER <username>[WITH][DBA|RESOURCE|CONNECT];
- 只有系统的超级用户才能授权创建一个新的数据库用户
- 新创建的数据库用户有三种权限:CONNECT,RESOURCE,DBA
- 如果创建时没有指定权限,默认为CONNECT权限。拥有CONNECT 权限的用户只能登录数据库。
- 拥有RESOURCE权限的用户能创建基本表和视图,成为所创建对象的属主,但不能创建模式,不能创建新用户。可以使用GRANT将权限授予给其他用户。
- 拥有DBA权限的用户是超级用户—无所不能。

4.2.5 数据库角色
数据库角色是被命名的一组与数据库操作有关的权限,角色是权限的集合。 使用角色来管理数据库权限可以简化授权的过程。
在SQL中首先用CREAT ROLE 语句创建角色,然后用GRANT语句角色授权,用REVOKE语句回收授予角色的权限。
1.角色的创建
CREAT ROLE <角色名>
2.给角色授权
GRANT <权限>[,<权限>]...
ON <对象类型> 对象名
TO <角色>[,<角色>]...
3.将一个角色授予给其他的角色或用户
GRANT <角色1>[,<角色2>]...
TO <角色3>[,<用户1>]...
[WITH ADMIN OPTION]
4.角色的回收
REVOKE <权限>[,<权限>]...
ON <对象类型><对象名>
FROM <角色>[,<角色>]...
CREAT ROLE R1;
GRANT SELECT,UPDATE,INSERT
ON RABLE Student
TO R1;GRANT R1
TO 王平,张明,赵玲;REVOKE R1
FROM 王平;
4.2.6 强制存取控制方法
强制存取控制是指系统为保证更高程度的安全性,按照TDI/TCSEC标准中安全策略的要求采取的强制存取检查手段。
在强制存取控制中,数据库管理系统所管理的全部实体被分为主体和客体两大类。
- 主体是系统中的活动实体,包括实际用户以及用户的各进程。
- 客体是系统中的被动实体,是受主体操纵的,包括文件,基本表,索引,视图等。
对于实体和客体,系统为他们每个实例指派一个敏感度被标记。敏感度标记分为若干级,绝密、机密、可信、公开等。
- 密级的次序是TS>=S>=C>=P。
- 主体的敏感度标记称为许可证级别,客体的敏感度标记称为密级。
- 强制存取控制就是通过对比主体的敏感度标记和客体的敏感度标记,最终确定主体是否能够存取客体。
要求:
- 仅当主体的许可证级别大于或等于客体的密级时,该主体才能读取相应的客体
- 仅当主体的许可证级别小于或等于客体的密级时,该主体才能写相应的客体
- 注意第2点,即用户可以写入数据但是不能再读取自己写入的数据。
那为什么高级别的主体(用户)不能写低级别的客体(文件)?
- 如果你是高级别的用户,如果可以写低级别的文件,那么很可能会把高级别的内容写入低几倍的文件中,从而造成了高级别的内容泄露(防止不怀好意的高级别用户有意泄露给低级别的用户)
4.3 视图机制
#建立计算机系学生的视图,把对该视图的SELECT权限授予王平,把该视图上的所有操作权限授予张明
CREAT VIEW CS_Student
AS
SELECT * FROM Student
WHERE Sdept='CS';GRANT SELECT
ON CS_Student
TO 王平;GRANT ALL PRIVILEGES
ON CS_Student
TO 张明;
4.4 审计
审计功能把用户对数据库的所有操作自动记录下来放进审计日记中。
审计员可以利用审计日记监控数据库中的各种行为,重现导致数据库现有现状的一系列事件,找出非法存取数据的人、事件和内容等,还可以进行防范。
AUDIT语句和NOAUDIT语句
AUDIT语句用来设置审计功能,NOAUDIT用来取消审计功能。审计又可分为用户级审计和系统级审计。
#对修改SC表结构或修改SC表数据的操作进行审计
AUDIT ALTER,UPDATE
ON SC;
#取消对SC表的一切审计
NOAUDIT ALTER,UPDATE
ON SC;
4.5 数据加密
数据加密主要包括存储加密和传输加密:
存储加密
- 一般提供透明和非透明两种存储加密方式:
- 透明存储加密是指内核级加密保护方式,对用户完全透明。在写到磁盘时对数据进行加密,授权用户读取数据时再对其进行解密。
- 非透明存储加密是通过多个加密函数实现
传输加密
- 在客户机/服务器结构中,为保证二者之间的安全数据交换,数据库管理系统提供了传输加密功能。常用的传输加密方式是链路加密和端到端加密。
- 链路加密
- 在链路层进行加密
- 传输信息由报文和报头两部分组成
- 报文和报头均加密
- 端到端加密
- 在发送端加密,接收端解密
- 只加密报文不加密报头
- 所需密码设备数量相对较少,容易被非法监听者发现并从中获取敏感信息。
第五章 数据库完整性
数据库的完整性是指数据的正确性和相容性。
5.1 实体完整性:保证了单表各条记录的可区分性
5.1.1 定义实体完整性
#将Student表中的Sno属性定义为码
CREATE TABLE Student(Sno char(9) PRIMARY KEY, #在列级定义主码Sname char(20) NOT NULL,Ssex char(2),Sage SMALLINT,Sdept CHAR(20)
);#或CREATE TABLE Student(Sno char(9), #在列级定义主码Sname char(20) NOT NULL,Ssex char(2),Sage SMALLINT,Sdept CHAR(20),PRIMARY KEY(Sno) #在表级定义主码
);
#注意:对多个属性构成的主码,只能定义为表级约束条件
5.1.2 实体完整性检查和违约处理
(1)检查主码的值是否唯一,如果不唯一则拒绝插入或修改
(2)检查主码的各个属性是否为空,只要有一个为空就拒绝插入或修改
一般检查如果通过全表扫描十分耗时。一般通过在主码上自动建立一个索引来提高效率。
5.2 参照完整性:实现不同表之间的参考联系
5.2.1 参照完整性定义
#定义SC中的参照完整性
CREATE TABLE SC(Sno CHAR(9) NOT NULL,Cno CHAR(9)NOT NULL,Grade SMALLINT,PRIMARY KEY(Sno,Cno), #在表级上定义实体完整性FOREIGN KEY(Sno) REFERNECES Student(Sno), #在表级上定义参照完整性FOREIGN KEY(Cno) REFERNECES Student(Cno) #在表级上定义参照完整性
);
5.2.2 参照完整性检查和违约处理

当发生上述操作,可以采取:
- 拒绝(NO ACTION)执行 默认策略
- 级联(CASCADE)操作
- 设置为空值
CREATE TABLE SC(Sno CHAR(9),Cno CHAR(4),Grade SMALLINT,PRIMARY KEY(Sno,Cno), #在表级定义实体完整性 Sno和Cno都不能为空值FOREIGN KEY(Sno) REFERENCE Student(Sno) #在表级定义参照完整性ON DELETE CASCADE #当删除Student表中的元组时,级联删除SC表中对应的元组ON UPDATE CASCADE #当更新Student表中的Sno时,级联更新SC表中相应的元组FOREIGN KEY(Cno) REFERENCE Course(Cno) #在表级定义参照完整性ON DELETE NO ACTION #当删除Course表中的元组造成与SC表不一致时,拒绝删除ON UPDATE CASCADE #当更新Course表中的Cno时,级联更新SC表中相应的元组
);
5.3 用户定义的完整性:常在创建表格时用CHECK自定义约束
前面已经有了元组约束条件,为什么还要有完整性约束子句?
- 元组约束条件只能适用于建表语句
- 完整性约束命名子句可用于建表语句或修改表定义语句(包括修改约束,删除约束,新增约束)
5.3.1 属性上的约束条件
1.属性上的约束条件定义
- 列值非空(NOT NULL)
- 列值唯一(UNIQUE)
- 检查列值是否满足一个条件表达式(CHECK短语)
CREATE TABLE Student(Sno CHAR(9) PRIMARY KEY, #在列级定义主码Sname CHAR(8) NOT NULL, #Sname属性不为空Ssex CHAR(2) CHECK(Ssex IN('男','女')), #性别属性Ssex只允许取男或女Sage SMALLINT,Sdept CHAR(20)
);
2.属性上约束条件的检查和违约处理
当往表中插入元组或修改属性的值时,关系数据库管理系统将检查属性上的约束条件是否满足,如果不满足则操作被拒绝执行
5.4 完整性约束命名子句:方便修改,在创建表格外还能修改
CONSTRAINT <完整性约束条件名><完整性约束条件>
CREATE TABLE Student(Sno NUMERIC(6)CONSTRAINT C1 CHECK(Sno BETWEEN 90000 AND 99999),Sname CHAR(20)CONSTRAINT C2 NOT NULL,Sage NUMERIC(3)CONSISTENT C3 CHECK(Sage<30),Ssex CHAR(2)CONSTRAINT C4 CHECK(Ssex IN('男','女')),CONSTRAINT StudentKey PRIMARY KEY(Sno),
);
2.修改表中的完整性限制
使用ALTER TABLE 语句修改表中的完整性限制
ALTER TABLE StudentDROP CONSTRAINT C4;
ALTER TABLE Student
DROP CONSTRAINT C1;
ALTER TABLE Student
ADD CONSTRAINT C1 CHECK(Sno BETWEEN 900000 AND 999999);
5.5 域中的完整性限制:命名域约束,从而可以用到多列上
#建立一个性别域,并声明性别域的取值范围
CREATE DOMAIN GenderDomain CHAR(2)CHECK(VALUE IN('男','女'));
#这样,对sex的说明改写为:
Ssex GenderDomain;
#建立性别域,并对其中的限制命名
CREATE DOMAIN GenderDomain CHAR(2)CONSTRAIN GD CHECK(VALUE IN('男','女'));
#删除GenderDomain的限制条件GD
ALTER DOMAIN Genderdomain DROP CONSTRAIN GD;
#删除原来的限制条件并在性别域增加限制条件GDD
ALTER DOMAIN GenderDomainDROP CONSTRAIN GD;
ALTER DOMAIN GenderDomainADD CONSTRAIN GDD CHECK('1','0');
5.6 断言:更一般化的约束,可以涉及多个表和聚集函数的约束
#限制每一门课程最多60名学生选修
CREATE ASSERTION ASS_SC_CNUM1CHECK(60>=(SELECT COUNT(*) FROM SC GROUP BY Cno));
5.7 触发器:定义一到多个表上DML数据操作事件驱动且自动调用的特殊过程
触发器是由用户定义在关系表上的一类由事件驱动的特殊过程。
- 触发器保存在数据库服务器中
- 任何用户对表的增、删、改操作均由服务器自动激活相应的触发器,在关系数据库管理系统和核心层进行集中的完整性控制。
- 触发器可以实现更为复杂的检查和操作,具有更精细和更强大的数据控制能力
触发器的优点
- 触发器是自动执行的,当用户对表中的数据作了任何修改之后立即被激活。
- 触发器可以通过数据库中的相关表进行层叠更改,实现多个表之间数据的一致性和完整性。
- 触发器可以强制限制,这些限制比用CHECK约束所定义的更复杂。
触发器的缺点
- 占用宝贵的数据库服务器资源,显著影响性能
- 将业务复杂化
- 显著加大平台迁移难度
5.7.1 定义触发器(CREATE TRIGGER)
#当触发事件发生时,该触发器被激活
CREATE TRIGGER<触发器名>
{BEFORE|AFTER}<触发事件>ON <表名>
REFERENCING NEW|OLD ROW AS<变量> #REFERENCING指出引用的变量
FOR EACH {ROW|STATEMENT} #定义触发器的类型,指明动作执行的频率
[WHEN<触发条件>]<触发动作体> #仅当触发条件为真时才执行触发动作体
#定义一个BEFORE行级触发器,为教师表Teacher定义完整性规则“教师的工资不低于4000元,如果低于4000,则改为4000”
CREATE TRIGGER Insert_Or_Update_Sal
BEFORE INSERT OR UPDATE ON Teacher #触发事件是插入或更新
FOR EACH ROW #行级触发器
BEGIN #定义触发动作体,是PL/SQL过程块IF(new.job='教授') AND (new.Sal<4000)THEN new.Sal:=4000END IF;
END;
#定义AFTER行级触发器,当教师表Teacher的工资发生变化后自动工资表Sal_log中增加一条相应的记录
#首先建立工资变化表Sal_log
CREATE TRIGGER Sal_log
(Eno NUMERIC(4) references teacher(eno),Sal NUMERIC(7,2),Username VARCHAR(10),Date TIMESTAMP
);CREATE TRIGGER Insert_Sal
AFTER INSERT ON Teacher #触发事件是INSERT
FOR EACH ROW
BEGIN INSERT INTO Sal_log VALUES(new.Eno,new.Sal,CURRENT_USER,CURRENT_TIMESTAMP);
END;
5.7.2 激活触发器
多个触发器,遵循如下的执行顺序:
- 执行该表上的BEFORE触发器
- 激活触发器的SQL语句
- 执行该表上的AFTER触发器
触发器优先级:
- 首先执行Before 语句级触发器,每条语句仅执行一次
- 其次执行Before行级触发器,为SQL语句影响的记录数的多少
- 再次执行After 行级触发器,为SQL语句影响的记录数是多少
- 最后执行是After 语句级触发器,每条语句仅执行一次
5.7.3 删除触发器
#删除教师表Teacher上的触发器
DROP TRIGGER Insert_Sal ON Teacher;
第六章 关系数据理论
针对一个具体问题,应该如何构建一个适合他的数据库模式,即应该构造几个关系模式,每个关系模式由哪些属性组成等——数据库逻辑设计问题——关系数据库规范化理论
关系数据库的规范化理论主要包括三个方面的内容:
- 函数依赖(核心作用,是模式分解和模式设计的基础)
- 范式(模式分解的标准)
- 模式设计
一个好的关系模式应该具备以下四个条件:
- 尽可能少的数据冗余
- 没有插入异常
- 没有删除异常
- 没有更新异常
6.2 函数依赖
数据依赖:关系模式中的各属性之间的相互依赖、相互制约的联系称为数据依赖。数据依赖一般分为函数依赖、多值依赖和连接依赖。
- 函数依赖:是关系模式中属性之间的一种逻辑依赖关系。
学生(学号(Sno),姓名(Sname),系名(Sdept)),并且,一个学号对应一个学生,一个学生只在一个系学习。也就是学号确定,那学生姓名和所在系也就确定了。类似于y = f ( x ) y=f(x)y=f(x),自变量x确定,y也就确定。Sname=f(Sno),Sdept=f(Sno),记作:Sno->Sname,Sno->Sdept
平凡函数依赖与非平凡函数依赖:
- 平凡的函数依赖:当属性集Y是属性集X的子集,则必然存在着函数依赖X->Y
- Y不是X的子集,则称X->Y为非平凡函数依赖
传递函数依赖:设有关系模式R(U),U是属性全集,X,Y,Z是U的子集,若X->Y,但Y-/->X而Y->Z,则称Z对X传递函数依赖:X-t->Z。如果Y->X,那么称Z对X直接函数依赖,而不是传递函数依赖。
函数依赖分为:
- 完全函数依赖
Sno->ID,Sno->Sname,Sno->SDept,SDept->SDeptM - 部分函数依赖
Sname部分依赖于(Sno,ID):只依赖于(Sno,ID)中任意一个
ID部分依赖于(Sno,Sname):只依赖于(Sno,Sname)中的Sno - 传递函数依赖
Sno->Sdept->SdeptM
范式(数据库关系设计达到要求的具体程度)
- 非规范化,1NF,2NF,3NF,BCNF(从低级到高级)
- 规范化(从低一级别往高一级别范式的分解过程)
6.3 关系模式的范式
关系模式分解后的好坏用什么标准衡量——范式

6.3.1 第一范式 1NF
是最基本的规范模式,即关系中的每个属性都是不可再分的简单项,即不存在表中有表的情况.
如果关系模式R所有的属性均为简单属性,即每个属性都是不可再分的,则称R属于第一范式,简称1NF,记作R∈1NF。
然而,一个关系模式仅属于第一范式是不适用的,比如SCD(SNO,CNO,Score,SN,Dept,MN,Age),有大量的数据冗余,插入异常,删除异常和更新异常等弊端。在SCD中,既存在完全函数依赖,也存在部分函数依赖,显然情况在数据库中是不允许的。克服这些弊端的方法是进行关系分解,去掉过于复杂的函数依赖关系,向更高一级的范式进行转换。

第一范式的目标是:将基本数据划分成称为实体集或表的逻辑单元,当设计好每个实体后,需要为其指定主码.

6.3.2 第二范式 2NF
如果关系模式R∈1NF,且每个非主属性都完全函数依赖于R的主关系键,则称R属于第二范式,简称2NF,记住R∈2NF。
2NF的缺点:
- 数据冗余
- 插入异常
- 删除异常
- 更新异常
第二范式的目标:将只部分依赖于候选码(即依赖于候选码的部分属性)的非主属性移到其他表中。

S-L-C这个函数依赖图中非主属性Sdept和Sloc部分函数依赖于码(Sno, Cno)

6.3.3 第三范式 3NF
如果关系模式R∈2NF,且每个非主属性都不传递函数依赖于R的主关系键


6.3.4 BC范式
通常认为BCNF是修正的第三范式,有时也称为扩充的第三范式。
一个满足BCNF的关系模式有:
- 所有非主属性都完全函数依赖于每个候选码
- 所有的主属性都完全函数依赖于每个不包含它的候选码
- 没有任何属性完全函数依赖于非码的任何一组属性
BCNF范式排除了:
- 任何属性(包括主属性和非主属性)对候选码的部分依赖和传递依赖;
- 主属性之间的传递依赖。
关系模式STJ(S,T,J)中,S表示学生,T表示教师,J表示课程。每一教师只教一门课,
每门课有若干教师,某一学生选定某门课,就对应一个固定的教师。
由语义可得到函数依赖:(S,J)→T;(S,T)→J;T→J
因为没有任何非主属性对码传递依赖或部分依赖,
STJ ∈ 3NF。
因为T是决定因素,而T不包含码,所以STJ 不属于 BCNF 关系。

第7章 数据库设计
- 需求分析:准确了解和分析用户需求(包括数据和处理)
- 概念结构设计:通过对用户需求进行综合、归纳与抽象,形成一个独立于具体DBMS的概念模型
- 逻辑结构设计:将概念结构转换为某个DBMS所支持的数据模型,并对其进行优化
- 物理结构设计:为逻辑数据模型选取一个最适合应用环境的物理结构(包括存储结构和存取方法)
- 数据库实施:根据逻辑设计和物理设计的结果建立数据库,编制与调试应用程序,组织数据入库并试运行
- 数据库运行和维护:在数据库投入正式使用后不断地对其进行评价、调整与修改

概念结构设计
设计概念结构通常有四类方法
-
自顶向下:即首先定义全局概念结构的框架,然后逐步细化
-
自底向上:即首先定义各局部应用的概念结构,然后将它们集成起来,得到全局概念结构
-
逐步扩张:首先定义最重要的核心概念结构,然后向外扩充
-
混合策略:即将自顶向下和自底向上相结合,用自顶向下策略设计一个全局概念结构的框架,以它为骨架集成由自底向上策略中设计的各局部概念结构。
逻辑结构设计
E-R图如何转换为关系模型?
-
(1)一个1:1联系可以转换为一个独立的关系模式,也可以与任意一端对应的关系模式合并。如果转换为一个独立的关系模式,则与该联系相连的各实体的码以及联系本身的属性均转换为关系的属性,每个实体的码均是该关系的码;如果与某一端实体对应的关系模式合并,则需要在该关系模式的属性中加入另一个关系模式的码和联系本身的属性。(联系本身的属性?)
-
(2)一个1:n联系可以转换为一个独立的关系模式,也可以与n端对应的关系模式合并。如果转换为一个独立的关系模式,则与该联系相连的各实体的码以及联系本身的属性均转换为关系的属性,而关系的码为n端实体的码
-
(3)一个m:n联系转换为一个关系模式。与该联系相连的各实体的码以及联系本身的属性均转换为关系的属性,各实体的码组成关系的码或关系码的一部分
第10章 数据库恢复技术
尽管数据库系统中采取了各种保护措施来防止数据库的安全性和完整性被破坏以及并发事务的正确执行,但某些故障仍然不可避免,会导致数据库中部分数据的丢失甚至破坏数据库,数据库恢复就是为了将数据库从错误状态恢复到某一已知的正确状态。
事务是用户定义的一个数据库操作序列,这些操作要么全做要么全不做,是一个不可分割的工作单位。例如在关系数据库中,一个事务可以是一条SQL语句、一组SQL语句。
事务通常是以BEGIN TRANSACTION开始,以COMMIT或ROLLBACK结束。COMMIT表示提交,ROLLBACK表示回滚,在事务运行的过程中发生某种故障事务不能继续执行,系统就会将事务对数据库的已完成操作全部撤销,从而回滚到事务开始时的状态。
事务的特性:
-
1.原子性:事务是数据库的逻辑工作单位,事务中包括的操作要么都做,要么都不做
-
2.一致性:事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。事务执行过程中出现故障则称这时的数据库处于不一致性状态。
-
3.隔离性:一个事务的执行不能被其他事务干扰,并发执行的各个事务之间不能互相干扰
-
4.持续性(永久性):一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。
事务的ACID特性可能遭到破坏的因素有:
- (1) 多个事务并行运行时,不同事务的操作交叉执行
- (2) 事务在运行过程中被强制停止
故障的种类
- 1.事务内部的故障:
- 2.系统故障:如操作系统故障,CPU故障,系统断电
- 3.介质故障:如磁盘损坏、磁头碰撞、瞬时强磁场干扰等
- 4.计算机病毒
恢复的实现技术及策略
数据转储
转储即DBA定期地将整个数据库复制到磁带或另一个磁盘上保存起来的过程。这些备用的数据称为后被副本。
转储分为:
- 静态转储:
静态转储必须等待正在运行的用户事务结束才能进行; - 动态转储
转储期间允许对数据库进行存取或修改,即转储和用户事务可以并发执行。
也可分为:
- 海量转储即每次转储全部数据库"
- 增量转储即每次只转储上一次转储后更新的数据。
登记日志文件(Logging)
日志文件是用来记录事务对数据库的更新操作的文件。不同数据库系统采用的日志文件格式并不完全一样,主要有两种格式:以记录为单位的日志文件和以数据块为单位的日志文件
对以记录为单位的日志文件,日志文件中需要登记的内容包括:
- 各个事务的开始(BEGIN TRANSACTION)标记
- 各个事务的结束(COMMIT或ROLLBACK)标记
- 各个事务的所有更新操作
以上每一条内容记为一个日志记录(log record)
每个日志记录的内容主要包括:
- 事务标识(标明是哪个事务)
- 操作的类型(插入、删除或修改)
- 操作对象(记录内部标识)
- 更新前数据的旧值(对插入操作而言,此项为空值)
- 更新后数据的新值(对删除操作而言,此项为空值)
恢复策略
REDO:重做,正向扫描日志文件,对每个REDO事务重新执行日志文件登记的操作
UDNO:撤销,反向扫描日志文件,对每个UNDO事务的更新操作执行逆操作
COMMIT:提交,将事务中所有对数据库的更新写回到磁盘上的物理数据库中,事务正常结束
ROLLBACK:回滚,事务运行的过程中发生了某种故障,事务不能继续执行,系统将事务中对数据库的所有已完成操作全部撤销,回滚到事务开始时的状态
事务故障的恢复
(1)反向扫描日志文件(即从最后向前扫描日志文件),查找该事务的更新操作
(2)对该事务的更新操作执行逆操作。(来得及或者未来得及写入数据库都没关系)
(3)继续反向扫描日志文件,查找该事务的其他更新操作,并做同样处理
(4)如此继续,直到读到该事务的开始标记
系统故障的恢复
(1)正向扫描日志文件,找出在故障发生前已经提交的事务(这些事务既有BEGIN TRANSACTION记录,也有COMMIT记录),将其事务标记记入REDO队列;同时找出故障发生时尚未完成的事务(这些事务只有BEGIN TRANSACTION记录,无相应的COMMIT记录),将其事务标记记入UNDO队列
(2)对撤销队列中的各个事务执行UNDO操作
(3)对重做队列中的各个事务执行REDO操作
为什么要REDO?考虑已提交事务对数据库的更新可能还留在缓冲区没来得及写入数据库(磁盘)。
介质故障的恢复:
(1)装入最新的数据库后备副本,使数据库恢复到最近一次转储时的一致性状态
(2)装入相应的日志文件副本(转储结束时刻的日志文件副本),重做已完成的事务,即扫描日志文件找出需要重做和撤销的事务

第十一章 并发控制
多事务执行方式:
- 事务串行执行
- 交叉并发方式(其实就是分时间片)
- 同时并发方式
并发控制概述

事务是并发控制的基本单位
并发控制机制的任务
- 对并发控制操作进行正确调度
- 保证事务的隔离性
- 保证数据库的一致性
- 丢失修改
- 不可重复读
- 读“脏”数据
记号
- R(x):读数据x
- W(x):写数据x
1、丢失修改
两个事务T1和T2读入同一数据并修改,T2提交的结果破坏了T1提交的结果,导致T1的修改丢失

2、不可重复读
不可重复读是指事务T1读取数据后,事务T2执行更新操作,使T1无法再现前一次的读取结果。

-
事务T1按一定条件从数据库中读取了某些记录之后,事务T2删除了其中的部分记录,当T1再次按相同的条件读取数据时,发现某些记录神秘消失了。
-
事务T1按一定条件从数据库中读取某些数据记录后,事务T2插入了一些数据,当T1再次按相同条件读取数据时,发现多了一些数据。
-
上面两种现象又称为”幻影”现象。
3、读“脏”数据
事务T1修改某一数据,并将其写回磁盘
事务T2读取同一数据后,T1由于某种原因被撤销
这时T1已修改过的数据恢复原值,T2读到的数据就与数据库中的数据不一样
T2读到的数据就是“脏”数据,即不正确数据

并发控制主要技术:
- 封锁(Locking)——最主要技术
- 时间戳(Timestamp)
- 乐观控制法
- 多版本并发控制(MVCC)
11.2 封锁
什么是封锁:
- 封锁就是事务T在对某个数据对象(例如表、记录等)操作之前,先向系统发出请求,对其加锁。
- 加锁之后事务T就对该数据对象有了一定的控制,在事务T释放他的锁之前,其他的事务不能更新此数据对象
- 封锁是实现并发控制的一个非常重要的技术
基本封锁类型:
排它锁(简记为X),又称为写锁
- 若事务T对数据对象A加上X锁,则只允许T读取和修改A,其他任何事务都不能再对A加任何类型的锁,直到T释放A上的锁
- 保证其他事务在T释放A上的锁之前不能再读取和修改A
共享锁(简记为S),又称为读锁
- 若事务T对数据对象A加上S锁,则事物T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁
- 保证其他事务可以读A,但在T释放A上的S锁之前不能对A进行任何修改
11.3 封锁协议
保持数据一致性的常用封锁协议
- 一级封锁协议:事务T在修改数据R之前必须先对其加X锁,直到事务结束才释放
- 二级封锁协议:一级封锁协议加上事务T在读取数据R之前必须先对其加S锁,读完后即可释放S锁
- 三级封锁协议:一级封锁协议加上事务T在读取数据R之前必须先对其加S锁,直到事务结束才释放。
三级协议的主要区别:
- 什么操作需要申请封锁以及何时释放锁(即持锁时间)
不同的封锁协议使事务达到的一致性级别不同
- 封锁协议级别越高,一致性程度越高

一级协议:(没有丢失数据修改)

二级协议(可以防止丢失修改和读“脏“数据)

三级封锁协议(防止数据丢失,防止读"脏“数据,不可重复读)

11.4 活锁和死锁
11.4.1 活锁
事务T1封锁了数据R
事务T2又请求封锁R,于是T2等待
T3也请求封锁R,当T1释放了R上的封锁之后系统首先批准了T3的请求,T2仍等待
T4来了,系统又批准,T2又等待…
…
T2有可能永远等待,这就是活锁的情形
避免活锁:采用先来先服务策略
- 当多个事务请求封锁同一数据对象时
- 按请求封锁的先后次序对这些事务排队
- 该数据对象上的锁一旦释放,首先批准申请队列中第一个事务获得锁
11.4.2 死锁
死锁:就是形成了环,T1等待T2,T2等待T1,T1和T2两个事务永远不能结束,形成死锁

两类方法:
- 死锁的预防:破坏产生的条件
- 一次封锁法:要求每个事务必须一次将所有要使用的数据全部加锁,否则不能继续执行
- 缺点
- 会降低并发度
- 难于事先精确确定封锁对象 - 顺序封锁法:预先对数据对象规定一个封锁顺序,所有事务都按这个顺序施行封锁
- 缺点
- 维护成本
- 难以实现
- 死锁的诊断与解除
- 超时法:如果一个事务的等待时间超过了规定限制,就认为发生了死锁
- 等待图法:用事务等待图动态反应所有事务的等待情况


11.5 并发调度的可串行性
11.5.1 可串行化调度
11.5.2 冲突可串行化调度
注:部分提纲来自julia_luofang
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
