目录
一.并发控制
作为共享资源的数据库,可以同时供很多用户使用。
在这样的系统中,同一时刻需要运行很多个事务,如何高效一致地执行这些事务是并发控制的工作。
当允许多个事务并发存取数据库时,如果不加以控制就有可能导致并发事务相互干扰,存取到不正确的数据,破坏数据库的一致性。
1.1并发操作引发的问题
在并发存取环境下,如果不同事务的两个操作均针对同一数据对象,且至少有一个是写操作,则称这两个操作是"冲突"的。
若对并发事务中的冲突操作不加控制,可能引发三类 问题:"丢失修改 "、"不可重复读 "、"读脏数据"
1.1.1丢失修改
当两个事务T1和T2 先后对同一数据对象A进行修改并写入数据库 时,后写入的结果会覆盖掉先写入的结果 ,导致先写入的事务修改结果丢失 ,即丢失修改问题。
丢失修改问题是由"写-写"冲突引起
1.1.2不可重复读
一个事务如果没有执行任何更新数据库数据的操作,则它们同一个查询操作执行两次或多次,结果应该是一致的 ,如果不一致,就说明产生了"不可重复读"。
例如:"事务T1连续两次读入数据A,事务T2在事务T1连续读入数据A的间隙,修改了数据A,造成事务T1两次读取的数据A结果不一致"。
不可重复读是由"读-写"冲突引起的。
1.1.3读"脏"数据
读"脏"数据 ,简称脏读,是指一个事务读取了另一个未提交的事务中的数据。
读"脏"数据是由"写-读"冲突引起的。
1.2调度及其可串行化
在并发访问情况下,当有多个事务并发执行时,其操作交叉执行的次序有很多种可能,因此需要有一个衡量并发调度正确与否的判断准则。
1.3事务的隔离性级别
SQL标准 定义了4种标准隔离级别 ,从低到高依次为:"读未提交 "、"读已提交 "、"可重复读 "、"可串行化"。
- 读未提交:最低的隔离级别,在这种事务隔离级别下,一个事务可以读到另外一个事务未提交的数据,不允许丢失修改,接收读脏数据和不可重复读现象。
- 读已提交:若事务还没提交,其他事物不能读取该事务正在修改的数据。不允许丢失修改和读脏数据,接受不可重复读现象。
- 可重复读:失误多次读取统一数据对象的结果一致,不允许丢失修改、读脏数据、读不一致、接受幻影读现象。
- 可串行化:最高级别的隔离性,保证可串行化,不允许丢失修改、读脏数据、读不一致以及幻影读现象的发生。
1.4封锁技术【重要】
封锁是实现并发控制的一种机制。
所谓封锁就是事务T在对某个数据对象操作之前先对其加锁 ,加锁后事务T就对该数据对象有一定程度的独占控制 ,在实物T释放锁之前,其它事务在操作数据对象时将会被拒绝。
最基本的封锁类型 有:"排他锁 "、"共享锁"两种。
1.4.1排他锁
排他锁 ,也称为X锁或者写锁。
若事务T对数据对象A加上X锁,则在加锁期间只允许T对数据对象A进行读取和修改。
1.4.2共享锁
共享锁 ,也称为S锁或读锁。
若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事物只能再对A加S锁,而不能加X锁,直到A上的S锁全部被释放。
排他锁 和共享锁 的封锁控制方式可以用下表表示:
其中:
- NL表示无锁
- X表示写锁
- S表示读锁
- T1/T2表示事务
1.5封锁协议
在运用X锁 和S锁 对数据对象加锁时,还需要约定一些规则,例如,何时申请X锁或S锁、持锁时间、何时释放等,这些规则称为"封锁协议"。
针对"读未提交 "、"读已提交 "、"可重复读 "、"可串行化 "四种事务隔离级别,可以通过下面的三级封锁协议和两段锁协议来实现。
1.5.1一级封锁协议
一级封锁协议 :事务T在修改数据R之前必须先对其加X锁,直到事务结束才释放。
事务结束包括正常结束(COMMIT )和非正常结束(ROLLBACK)
一级封锁协议只能解决"丢失修改"问题
1.5.2二级封锁协议
在一级封锁协议 的基础上,再加上事务T在读取数据R之前必须先对其加S锁,读完后即可释放S锁。
二级封锁协议 解决:"丢失修改"、"读脏数据"
1.5.3三级封锁协议
在一级封锁协议 的基础上,再加上事务T在读取数据R之前必须先对其加S锁,直到事务结束才释放。
三级封锁协议 解决:"丢失修改"、"读脏数据"、"不可重复读"
上面的三级封锁协议,不能解决"插入和删除的幻影读现象"
1.5.4两段锁协议
两段锁协议(2PL协议) ,是一种能够实现并发调度可串行化的封锁协议。
- 在任何数据对象进行读、写操作之前,事务要获得对数据对象的加锁。
- 在释放任意一个锁之后,事务不再允许获得任何其他加锁。
在遵守两段锁协议事务 中,明显地可分为两个阶段 :第一阶段是锁逐步增加阶段,称为扩展阶段。第二阶段是锁逐步释放阶段,称为收缩阶段。
如果遵守2PL的调度,将锁释放都放在事务结束,则可避免发生连锁回滚 和不可重复读问题。
"把所有锁都放在事务结束时释放的两段锁协议称为严格的2PL协议 ",大多数DBMS都采用严格的2PL。
1.6死锁与活锁问题
1.6.1死锁
如果系统中有两个 或两个 以上的事务都处于等待状态,并且每个事务都在等待其中另一个事务解除封锁 ,它才能够继续执行下去,结果造成任何一个事务都无法继续执行,这种现象称为系统进入了"死锁"。
在数据库系统中死锁很少发生,即使发生也涉及很少几个事务。
死锁检测的方法一般有下列两种:
- 超时法:如果一个事务的等待时间超过某个时限,则认为发生死锁
- 等待图法:动态维护一个等待图,如果等待图中出现回路,则存在死锁
1.6.2活锁
系统可能使某个事务永远处于等待状态,得不到封锁的机会,这种现象称为系统进入了"活锁"。
解决活锁的方法:
- 先来先服务策略,封锁子系统对请求封锁的先后次序进行排队,以此获得锁。
1.7封锁的粒度
在数据库中,封锁的数据对象 可以是:"逻辑单元 "(属性、属性集、元组、关系、索引项、整个索引、整个数据库),也可以是物理单元 ,例如:"页、块、存储区域"等。
封锁数据对象 的大小称为"封锁的粒度"。
封锁粒度越大,封锁处理越简单,系统开销也越小,但这样往往把无需加锁的数据也封锁了,反之。
二.数据库安全性
数据库系统 通常采取的安全措施 包括:"用户标识与鉴别 "、"存取控制 "、"视图机制 "、"数据加密 "、"审计"。
2.1用户标识与鉴别
用户标识与鉴别是系统提供的最外层安全保护措施。
即使用"用户名+密码"的方式来登录数据库才可以进行操作
2.2存取控制
存取控制是确保具有授权资格的用户访问数据库,同时使所有未被授权的人员无法访问数据库的机制。
数据库用户按照访问权利 的大小,可以分为三类:
- 一般数据库用户:通过授权可以对数据库进行操作的用户
- 数据库的拥有者:数据库的拥有者即数据库的创建者,除了一般数据库用户的权利外,还可以授予或收回其他用户对其所创建数据库的存取权。
- 有DBA特权的用户:拥有支配整个数据库资源的特权,对数据库拥有最大的特权。
2.3视图机制
通过为不同的用户定义不同的视图,可以将要保密的数据对无权存取的用户隐藏起来,从而自动地给数据提供一定程度的安全保护。
2.4数据加密
加密技术是防止数据库在存储或传输中失密的有效手段。
基本思想是:"根据一定的算法将原始数据变成不可直接识别的格式,再在数据库端解码"
2.5审计
审计功能可以把用户对数据库的操作自动记录下来放入审计日志 ,有时也被称作"审计跟踪",系统能利用审计跟踪的信息,重现导致数据库现状的一系列事件,以找出非法存取数据的人。
三.数据库完整性
数据库的完整性 是指数据库中的数据"正确性 "和"相容性",即为了防止数据库中存在不符合语义的数据,防止错误信息的输入和输出。
为了实现数据库完整性 ,DBMS 必须提供表达完整性约束的方法。
3.1完整性约束条件的类型
完整性约束条件 作用的对象可以是列、元组、关系三种。
完整性约束条件 的类型可以分为两大类型 :"静态约束"和"动态约束"。
3.1.1静态约束
静态约束 是指数据库每一确定状态时的数据对象所应满足的约束条件,它是反应数据库状态合理性的约束,这是最重要的一类完整性约束。
而静态约束作用的对象 不同,又可分为三种:
- 静态列约束:静态列约束是对一个列的取值域等的说明或限制。
- 静态元组约束:规定组成一个元组的各个列之间的约束。
- 静态关系约束:反映了一个关系中各个元组之间或者若干关系之间的约束。
3.1.2动态约束
动态约束 是指数据库从一种状态转变为另一种状态时,新、旧值之间所满足的约束条件。
- 动态列约束:规定修改列定义或列值时应满足的约束条件。
- 动态元组约束:修改某个元组的值时元组中的各个字段之间要满足某种约束条件。
- 动态关系约束:在关系变化时的限制条件,例如:"事务一致性"、"原子性"等约束条件。
3.2完整性控制机制的功能
DBMS的完整性控制机制应该具有如下三个方面的功能。
3.2.1定义功能
提供定义完整性约束条件的机制。
3.2.2检查功能
检查用户发出的操作请求是否违反了完整性约束条件。
检查是否违背完整性约束条件通常是在一条语句执行后立即检查,这类约束称为"立即执行的约束"。
如果某个检查需要延迟到整个事务结束后再进行,这类约束称为"延迟执行的约束"。
3.2.3保护功能
如果发现用户的操作请求违背了完整性约束条件,则采取一定的保护动作来保证数据的完整性。
3.3完整性约束的表达方式
3.3.1在创建和修改基表模式时说明约束
SQL中的关键字
在CREATE TABLE 中声明某个属性或属性集作为某个关系的关键字,主要有两种方法:"使用PRIMARY KEY(主关键字) "、"使用保留字UNIQUE"。
在一个表中只有一个"PRIMARY KEY ",但可以有多个"UNIQUE"。
参照完整性和外部关键字
参照完整性是关系模式的另一种重要约束。
参照完整性有两个要求:
- 被参照的第二个关系的属性必须是该关系的主关键字。
- 对于第一个关系中外关键字的任何值,也必须出现在第二个关系的相应属性上。
维护参照完整性约束的策略有下面三种:
- 默认策略:拒绝违规的更新。
- 级联策略:被参照关系中元组修改的同时,参照关系中元组也会自动的修改,保持一一对应的原则。
- 置空策略:对于被参照关系的删除和修改操作时独立进行的,这时可以采用置NULL策略,方法是在模式后面加上"ON DELETE SET NULL"或"ON UPDATE CASCADE"。
属性值的约束
属性值的约束 表达方式是:"在关系模式的定义中对属性进行约束 "、"首先约束某个域,然后再说明它是某个属性的域"。
- 非空约束:限制属性值不为空,在后面加一个"NOT NULL"
- 基于属性值检查的约束:该属性上的每一个值都要满足"CHECK后面的条件",在后面加一个"CHECK (<条件>)"
- 域约束:声明一个域来约束某个属性的取值。
全局约束
一个复杂的约束条件可能涉及几个属性甚至几个不同关系之间的联系,称为全局约束。
3.4用断言说明约束【了解即可】
一个断言就是一个谓词 ,用以说明数据库状态必须满足的一个条件。
在SQL 中可以使用"ASSERTION "语句来说明断言,形式为:
不管什么样的数据库操作,只要它破坏了断言中的条件 (使条件为假),系统就拒绝执行。
3.5用过程说明约束
在应用程序中插入一些过程,以检验数据库更新是否违背给定的约束。
如果违背约束,则回滚事务。