7.1 事务
一个事务由应用程序中的一组操作序列组成,在程序中,事务以Begin Transaction开始,以Commit/Rollback结束
原子性——DBMS事务管理子系统负责
一致性——DBMS完整性子系统负责
隔离性——DBMS并发控制子系统负责
持久性——DBMS恢复管理子系统负责
事务的状态变迁图
活动:事务开始执行后进入活动状态
局部提交:事务的最后一个语句结束后,进入局部提交状态,这时虽然执行完了,但是对数据库的修改,可能还留在内存的系统缓冲区中
失败状态:处于活动状态的事务还没有达到最后一个语句就中止执行了/处于局部提交状态的事务遇到了故障
异常中止状态:处于失败状态的事务,可能已经对磁盘的一部分数据做了修改,这时要进行回退ROLLBACK,回退完了就进入了异常中止
异常中止和提交状态都是结束状态
7.2 数据库的恢复
- 系统能把数据库从被破坏、不正确的状态恢复到最近一个正确的状态,DBMS叫这种能力为数据库的可恢复性
- 存储器分为
- 易失性存储器(内存、Cache)发生故障时信息丢失
- 非易失性存储器(磁盘、磁带)系统发生故障时不会丢失存储的信息,但是本身发生故障时会丢失
- 稳定存储器,一个理论概念
- 稳定存储器如何实现
- 数据备份(磁盘镜像、磁盘阵列、双机容错、数据备份)
- 数据银行(传到远端)
- 数据库的恢复的基本原则:冗余,即数据库重复存储
- 数据库恢复具体方法
- 转储
周期性的对整个数据库进行复制,转储到另一个磁盘或磁带一类的存储介质中 - 建立日志
- 转储
- 如果数据库遇到灾难性故障,如磁头脱落、磁盘损坏,这时数据库不能用,则使用最近一次备份的整个数据库,在利用日志,进行REDO重做已提交的事务
- 如果数据库只是破坏了一致性(某些数据不正确),用日志撤销UNDO不可靠的修改,重做REDO已提交的、但是可能还留在内存缓冲区没写尽磁盘的事务
-故障类型
事务故障
1)对于可以预期到的错误,如余额透支,可以在代码中加入判断语句,不符合就Rollback,当事务执行到rollback时,就是undo操作
2) 对于无法预期的错误,如运算溢出、数据错误、并发事务出现死锁,就由系统直接对该事务执行undo操作
系统故障(软故障)
1)对未完成的事务undo
2)对已完成但更新还留在缓冲区的事务进行redo
介质故障(硬故障)
1)重装最近转储的后备副本到新的磁盘,将数据库恢复到转储时的状态
2)在日志中找出转储后所有提交的事务进行REDO
事务故障和系统故障由系统自动执行,而介质故障要DBA配合执行
- 检查点
DBS运行时,由DBMS定时设置检查点,在检查点时刻真正做到对DB对的修改写进磁盘,并在日志中加一条检查点记录,当DB需要恢复时,只有在检查点后面的时候才需要恢复。
如果在检查点后故障点前做完的,就Redo,如果在故障点还没做完的,undo - 检查点恢复算法
- 根据日志文件建立事务重做队列和事务撤销队列
正向扫描,找出故障点前已经提交的事务,加入重做队列;找到故障点时还没提交的事务,加入撤销队列 - 正向扫描日志文件,根据重做队列的记录对每一个重做事务重新实施对数据库的更新操作
- 反向扫描日志文件,根据撤销队列的记录对每一个撤销事务的更新操作执行逆操作(对插入操作执行删除操作,对删除操作执行插入操作,对修改操作用修改前的值代替修改后的值)
- 根据日志文件建立事务重做队列和事务撤销队列
7.3 数据库的并发控制
-
并发操作带来的三个不一致
把未提交(Commit)的随后被撤销的数据叫做脏数据
-
采用封锁技术/时标技术解决
-
封锁技术
锁的作用是使并发事务对数据库中数据项的访问能够同步-
排他型封锁(X锁、写锁、Exclusive Lock)
-
定义:如果事务T对某个数据R(数据项/记录/数据集/数据库)加了X锁,那么在T解锁之前,不允许其他任何事务T再对该数据加任何类型的锁,但是!!!事务还可以使用基本select语句对数据进行查询。只有当数据被加了共享锁,没有对数据继续加共享锁的事务是不能通过select查询数据的。
-
使用X锁的操作:
1、申请X锁 “XFIND R”;申请成功才能读或写数据R
2、解除X锁 “XRELEASE R”
系统将解锁操作合并到Commit/Rollback中,以保证正确性
-
-
共享型封锁(S锁、读锁、Shared Lock)
- 定义:如果事务T对某数据加上S锁,仍允许其他事务在对该数据加S锁,但在对数据的所有S锁解除之前不允许任何事务对该数据加X锁
- 使用S锁的操作:
1、申请S锁 “SFIND R” 如果申请成功,则可以读R,不可以写R
2、升级和写操作 “UPDX R” 把对R的S锁升级为X锁,若成功,则更新数据R
3、解除S锁 “SRELEASE R” 解除对R的S锁
-
封锁的相容矩阵
-
封锁的粒度
1、封锁的对象可以是逻辑单元,也可以是物理单元。如属性值、元组、关系、索引项、数据库等,也可以是页、块等物理单元;
2、封锁对象的大小叫做封锁的粒度;
3、封锁的粒度越大,并发度越小,系统开销越小;封锁的粒度越小,并发度越大,系统开销越大;
4、处理大量元组的用户事务可以以关系为封锁单元;处理少量元组的用户事务可以以元组为封锁单元提高并发度; -
封锁协议
封锁协议都要求事务在修改数据前要对数据加X锁,直到事务结束才释放-
一级封锁协议
对只读事务可以不加锁
优点:防止了丢失修改
缺点:不加锁的事务,可能脏读、可能不可重复读
解决了丢失修改:事务A在对数据D加X锁后,直到它释放前,其他事务不允许再对数据D进行修改,于是解决了丢失修改问题;
================================================================没解决脏读:事务A对数据D加了X锁,数据D是不存在S锁的。事务B仍然可以通过基本的select语句查询,如果事务A修改了数据,但未提交事务,这期间,B事务查询到了修改后的数据,然后事务A回滚了,这样就形成了脏读。
================================================================没解决不可重复读:事务B在事务A对数据D的修改前后分别去读,就出现了不可重复读
-
二级封锁协议
其他事务在读数据时必须加S锁,读完数据后即释放S锁
优点:防治了丢失修改、脏读
缺点:对加S锁的事务,可能不可重复读
解决了丢失修改:事务A在对数据D加X锁后,直到它释放前,其他事务不允许再对数据D进行修改,于是解决了丢失修改问题;
================================================================解决了脏读:事务A对数据D加了X锁,B想要去访问数据D必须加S锁,但是加完X锁后不允许事务B再对数据D加S锁了,B都不能读D,自然不会脏读
================================================================没解决不可重复读:首先,事务B对数据D加共享锁读数据D,然后释放共享锁,但是B没有提交,这时事务A再对数据D加排他锁进行修改,然后事务A提交,释放排他锁,然后事务B再对数据D加S锁读取,读取到修改后的结果,与上一次读取不一致。
-
三级封锁协议
读数据是要加S锁,直到事务结束才能释放S锁
优点:防止丢失修改、脏读、不可重复读
缺点:降低并发度
事务在执行期间,只允许有一把锁,要么是X锁,要么是S锁,加了S锁,就在事务执行期间就不能被修改,所以多次读也是一样的
-
-
封锁带来的问题
-
活锁
系统使某个事务永远处于等待状态,得不到封锁的机会
解决活锁问题可采用先来先服务的策略 -
饿死
有可能存在一个事务序列,其中每个事务都申请对某数据项加S锁,且每个事务在授权开锁后的一小段时间内释放封锁,此时若有另一个事务T2想对该数据项加X锁,则将永远轮不上封锁的机会,这就是饿死。 -
死锁
系统中有两个或两个以上事务都处于等待状态,且每个事务在等待其中另一个事务解除封锁,它才能继续执行下去,结果造成任何一个事务都无法继续执行,这样的状态就是死锁
-
-
-
事务调度
对于有n个事务串行调度,可以有n!中不同的有效调度,且事务串行调度的结果都是正确的
对于有n个事务并发调度,可能的并发调度数目远远大于n!,其中有些正确、有些错误,根据DBMS的并发控制子系统决定可串行调度一定是正确的调度,但是正确的调度不一定是可串行的调度,因为可串行化要求更严格
-
SQL对数据并发处理的支持
- 事务的存取模式
- READ ONLY
用SQL语句定义
SET TRANSACTION READ ONLY
表示事务对数据库的操作只能是读操作,定义这个模式后,随后的事务都是只读 - READ WRITE
SET TRANSACTION READ WRITE(默认)
表示事务对数据库可读可写
- READ ONLY
- 事务的隔离级别
- SERIALIZABLE(可串行化)相当于3级协议
允许事务与其他事务并发执行,但是系统必须保证并发调度是可串行化的(默认)
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; - REPEATABLE READ(可重复读)相当于2级协议
只允许事务读已提交的数据,且在两次读同一个数据时不允许别的事务修改该数据
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; - READ COMMITTED(读提交数据)相当于1级协议
允许事务读已提交的数据,但是不要求可重复读
SET TRANSACTION ISOLATION LEVEL READ COMMITTED; - READ UNCOMMITTED(读未提交数据) 相当于0级协议
允许事务读已提交或未提交的数据
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
- SERIALIZABLE(可串行化)相当于3级协议
- 事务的存取模式
7.4 数据库的完整性
-
完整性包括 正确性、有效性、相容性 (cvc:correct、valid、consistent)
-
正确性指数据的合法性,如数值型数据只能含有数字而不含字母
-
有效性指数据是否属于所定义的有效范围,如岁数0-150内
-
相容性指表示同一事实的两个数据应相同
-
DBMS必须提供一种功能来保证数据库中的数据是争取的,避免非法的不符合语义的错误数据的输入输出 即 垃圾进垃圾出 Garbage In Garbage Out
-
检查数据库中的数据是否满足规定的条件 — 完整性检查
-
数据库中的数据应该满足的条件 — 完整性约束条件/完整性规则
-
完整性子系统按照 完整性规则集 工作
-
完整性规则集由 DBA / 应用程序员 事先定义
-
SQL中将完整性约束分成
- 域约束
- 基本表约束
- 断言
-
域约束(之前在第三章整理过)
用CREATE DOMAIN定义新的域
比如
create domain color char(6) default '???'
constraint valid_colors check (
value in ('Red','Yellow','Blue','Green','???')
);
然后后面创建表的时候,可以直接
create table s
(sno char(4),
cno char(4),
color color);
之后若用户插入一条记录的时候,没有写color值,会默认填上 ???
如果输入非法颜色值,会报错
-
基本表约束
基本表约束主要有三种形式:候选键定义、外键定义、检查约束定义- 候选键定义
UNIQUE(列名) / PRIMARY (列名)
UNIQUE实际上定义了表的候选键,但是只表示了该值唯一,并没有规定该值不可以为空,值非空要在定义后面加NOT NULL
create table s (sno char(4), cno char(4) NOT NULL, color color, PRIMARY (sno) UNIQUE(cno));
- 外键定义
FOREIGN KEY(列名) REFERENCES 参照表(列名) 【ON DELETE 动作】【ON UPDATE 动作】
动作有- NO ACTION
对依赖表没有影响 - CASCADE
删除参照表中的元组时,将依赖表中和参照表中主键相同的元组一起删除 - RESTRICT
只有当依赖表中没有一个外键和参照表中要删除的元组主键一致时才删除 - SET NULL
删除参照表元组时,对应的依赖表中外键值置空 - SET DEFAULT
删除参照表元组时,对应的依赖表中外键值置默认值
- NO ACTION
create table s (sno char(4), cno char(4), color color, PRIMARY (sno), FOREIGN KEY(cno) REFERENCES Course(cno) on delete no action on update cascade );
- 检查约束定义
使用check
check不好的一点在于,要尽可能不要涉及其他关系,比如在SC表中规定,插入的元组的S#一定要在S表中,但是插入后S表删去了对应的S# 对应的元组,这个错误是发现不了的 - 断言
create assertion 断言名 check(…)
drop assertion 断言名
断言比检查子句更能保证不出差错
- 候选键定义
#每位老师开设课程不超过10门
CREATE ASSERTION AX CHECK(
10 >= ALL(SELECT COUNT(Cno)
FROM C
GROUP BY Tno ));
#不允许男同学选WU老师的课
CREATE ASSERTION AX CHECK(
NOT EXIST (SELECT *
FROM SC
WHERE Cno IN (SELECT Cno
FROM C,T
WHERE C.Tno = T.Tno AND TNAME='WU')
AND
Sno IN (SELECT Sno
FROM S
WHERE SEX = 'M')));
- 触发器
7.5 数据库的安全性
-
数据库的安全性是指保护数据库,防止不合法的使用,以免数据的泄密、更改或破坏
-
安全性是保护数据以防止非法用户故意造成的破坏,完整性是保护数据以防止合法用户无意造成的破坏
-
安全性的五个级别(从低到高)
环境级==》职员级 ==》OS级==》网络级==》DBS级 -
用户使用数据库的方式叫做权限
-
权限分为访问数据的权限和修改数据库结构的权限
- 访问数据的四个权限
- 读Read
- 插入Insert
- 修改Update
- 删除Delete
- 修改数据库模式的权限
- 索引权限:允许用户创建和删除索引
- 资源权限:允许用户创建新的关系
- 修改权限:允许用户在关系结构中加入或删除属性
- 撤销权限:允许用户撤销关系
- 访问数据的四个权限
-
SQL中的安全性机制
-
视图
- 视图从一个或多个基本表中导出
- 视图本身没有数据,不占磁盘空间
- 视图机制有三个优点
- 数据安全性
- 逻辑数据独立性
- 操作简便性
- 第三章第五节有对视图更完整的叙述
-
权限
- 用户权限有六个:SELECT、INSERT、UPDATE、DELETE、REFERENCES、USAGE
- REFERENCES允许用户定义新关系时,引用其他关系的主键为外键
- USAGE 允许用户使用已经定义的域
- 如果授权全部权限,就用ALL PRIVILEGES
- GRANT 权限 ON 数据库元素(关系、视图、域,域前要加DOMAIN)TO 用户名 【WITH GRANT OPTION】
- 例子
- GRANT SELECT,UPDATE ON S TO WANG WITH GRANT OPTION
- GRANT INSERT(S#,C#) ON SC TO Lou WITH GRANT OPTION
- GRANT UPDATE(SCORE) ON SC TO Wen
- GRANT REFERENCES(C#) ON C TO Bao WITH GRANT OPTION(Bao在创建新关系的时候可以把C的主键C#作为新关系的外键)
- GRANT USAGE ON DOMAIN AGE TO PUBLIC(让所有用户(当前和将来)使用已经定义过的域age)
- 收回权限 REVOKE 权限 ON 数据库元素(关系、视图、域,域前要加DOMAIN)FROM 用户名 【CASCADE|RESTRICT】
- REVOKE 可以用REVOKE GRANT OPTION FOR代替
意思是回收转授出去的转授权限(grant option权),不是回收转授出去的权限 - 例子
- REVOKE SELECT, UPDATE ON S FROM WANG CASCADE; (连锁回收)
- REVOKE INSERT(S#,C#) ON SC FROM Luo RESTRICT; (如果Luo把权限转授给了别人,那么回收失败)
- REVOKE GRANT OPTION FOR REFERENCES(C#) ON C FROM Bao;不再让Bao能拥有Grant option
-
角色 ROLE
- 用户是实际的人或者访问数据库的应用程序
- 角色是一组具有相同权限的用户
- SQL没有CREATE USER、DROP USER等语句,由具体的系统确定如何创建和撤销用户
- 用户和角色是多对多的关系,一个用户可以参与多个角色,一个角色可以授权给多个用户
- 可以用GRANT语句将权限授给角色,再把角色授予用户,使用户具有权限
- 也可以把一个角色A授予另一个角色B,让B有A的权限
-
审计
- 出于安全性目的的数据库日志叫做审计追踪
- 审计追踪是一个对数据库做更改的日志
-