事务管理控制(上):https://developer.aliyun.com/article/1529557
2.4 并发控制技术
并发事务如果对数据读写时不加以控制,会破坏事务的隔离性和一致性。为了保持事务的隔离性,系统必须对事务之间的相互作用加以控制,最典型的方式 是要求对数据对象以互斥的方式进行访问,即当一个事务访问某个数据对象时,其他事务都不能更新该数据对象。最常用的控制的手段就是加锁,该方法是只允许事务访问当前持有锁的数据项。
给数据对象加锁的方式有多种,主要有排它锁和共享锁。
排它锁 (Exclusive Locks,简称X锁)也称为写锁,用于对数据进行写操作时进行锁定。 如果事务T对数据A加上义锁后,就只允许事务T读取和修改数据A,其他事务对数据A不能再加任何锁,从而也不能读取和修改数据A,直到事务T释放A上的锁。
共享锁(Share Locks,简称S锁)也称为读锁,用于对数据进行读操作时进行锁定。如果事务T对数据A加上了S锁后,事务T就只能读数据A但不可以修改,其他事务可以再对数据A加S锁来读取,只要数据A上有S锁,任何事务都只能再对其加S锁读取而不能加X锁修改。
2.5 两段锁协议
通过对数据加锁,可以限制其他事务对数据的访问,但这会降低事务的并发性。如何在保证事务的一致性的前提下尽可能地提高并发性,这需要封锁协议来解决。封锁协议是对数据加锁类型、加锁时间和释放锁时间的一些规则的描述。
1)三级封锁协议
封锁协议有三个级别:一级封锁协议、二级封锁协议和三级封锁协议。
一级封锁协议:是事务T在修改数据A之前必须先对其加X锁,直到事务结束才释放X锁。一级封锁协议使得在一个事务修改数据期间,其他事务不能对该数据进行修改,只能等到该事务结束,解决了丢失修改的问题。
二级封锁协议:是一级封锁协议加上事务T在读取数据A之前必须对其加上S锁,读完后即可释放S锁。二级封锁协议使得一个事务不能读取被其他事务修改中的数据。解决了读脏数据的问题。但是,如果事务T在读取数据A之后,其他事务再对A做完修改,事务T再读取A,还会产生不可重复读的错误。
三级封锁协议:是一级封锁协议加上事务T在读取数据A之前必须对其加上S锁,直到事务结束才释放S锁。三级封锁协议使得一个事务读取数据期间,其他事务只能读取该数据而不能修改,解决了不可重复读的问题。
2)两段锁协议
两段锁协议是指对任何数据进行读写之前必须对该数据加锁;在释放一个封锁之后,事务不再申请和获得任何其他封锁。
所谓“两段”锁的含义是:事务分为两个阶段。第一阶段是获得封锁,也称为扩展阶段;第二阶段是释放封锁,也称为收缩阶段。
为了确保事务并行执行的正确性,许多系统采用两段锁协议。同时系统设有死锁检测机制。发现死锁后按一定的算法解除死锁。
如果事务都遵循两段锁协议,那么它们的并发调度是可串行化的。两段锁是可串行化的充分条件,但不是必要条件。即如果事务不遵循两段锁协议,那么它们的并发调度可能是可串行化的,也可能是不可串行化的。
需要注意的是采用两段锁协议也有可能产生死锁,这是因为每个事务都不能及时解除被它封锁的数据,可能会导致多个事务互相都要求对方已封锁的数据不能继续运行。
2.6 多粒度封锁协议
封锁对象的大小称为封锁的粒度。
封锁的对象可以是逻辑单元(如属性、元组、关系、索引项、整个索引直至整个数据库),也可以是物理单元(如数据页或索引页)。
封锁粒度与系统的并发度和并发控制的开销密切相关。封锁的粒度越大,并发度越小,但系统开销也就越小;封锁的粒度越小,并发度越高,但系统开销也就越大。
选择封锁粒度时必须同时考虑封锁对象和并发度两个因素,对系统开销与并发度进行权衡,以求得最优的效果。一般说来,需要处理大量元组的用户事务可以以关系为封锁对象;需要处理多个关系的大量元组的用户事务可以以数据库为封锁对象;而对于一个处理少量元组的用户事务,可以以元组为封锁对象以提高并发度。
多粒度(multipl egranularity)机制是指通过允许各种大小的数据项并定义数据粒度的层次结构,其中小粒度数据项嵌套在大粒度数据项中。对此,可以构造一个粒度层次图,粒度层次图像一棵倒置的树,故也称多粒度树。
采用多粒度树的好处是:减少对后代结点加锁的系统代价
意向锁是与共享锁和排它锁相关联的另一种锁。
多粒度封锁协议(multiple-granularity looking protocol)允许多粒度树中的每个结点被独立地加锁,对某结点加锁意味着该结点的所有后代结点也被加了同类型的锁。
. 数据库的备份与恢复
数据库的运行过程中,难免会出现计算机系统的软、硬件故障,这些故障会影响数据库中数据的正确性,甚至破坏数据库,使数据库中全部或部分数据丢失。 因此,数据库的关键技术在于建立冗余数据,即备份数据
。如何在系统出现故障后及时使数据库恢复到故障前的正确状态,就是数据库恢复技术。
3.1 数据库系统故障
数据库系统中可能发生的故障有很多,主要有事务故障、系统故障和介质故障。
1)事务故障
事务故障(transaction failure)是由于程序执行错误而引起事务非预期的、异常终止的故障。
主要有如下两类错误:
(1)逻辑错误。如非法输入、找不到数据、溢出、超出资源限制等原因引起的事务执行失败。
(2)系统错误。系统进入一种不良状态(如死锁),导致事务无法继续执行。
对于不可以预期的错误应用程序无法处理,是由 DBMS 系统实现故障恢复的。
事务故障意味着事务没有达到预期的终点(COMMIT 或者显示 ROLLBACK),因此数据库可能处于不正确状态。恢复程序要在不影响其他事务运行的情况下,强行回滚该事务,即撤销该事务已经做出的任何对数据库的修改,这类恢复操作称为事务撤销(UNDO)。
2)系统故障
系统故障是指硬件故障、软件(如 DBMS、OS 或应用程序)漏洞的影响,导致丢失了内存中的信息,影响正在执行的事务,但未破坏存储在外存上的信息。这种情况称为故障-停止假设(fail-stop assumption)。
系统故障中止了事务的执行过程,破坏了事务的原子性,由于缓冲区中的内容可能部分已写入数据库,系统重启后数据库可能处于不一致状态。
3)介质故障
介质故障是指数据库的存储介质发生故障,如磁盘损坏、瞬间强磁场干扰等。这种故障直接破坏了数据库,会影响到所有正在读取这部分数据的事务。
3.2 数据库的备份
数据是资产,备份最重要。数据转储是将数据库自制到另一个磁盘或磁带上保存起来的过程,又称为数据备份。数据的备份分为静态转储和动态转储、海量转储和增量转储。
(1)静态转储和动态转储。静态转储是指在转储期间不允许对数据库进行任何存取、修改操作;动态转储是在转储期间允许对数据库进行存取、修改操作,因此,转储和用户事务可并发执行。数据转储可以由系统管理员(DBA)来操作,如静态转储,可以设定时间计划由 DBMS 定时执行,可以在事务程序中增加功能实现动态转储,也可以通过硬件系统的冗余磁盘阵列来实现。
(2)海量转储和增量转储。海量转储是指每次转储全部数据;增量转储是指每次只转储上次转储后更新过的数据。
(3)日志文件。在事务处理的过程中,DBMS把事务开始、事务结束以及对数据库的插入、删除和修改的每一次操作写入日志文件。每条记录包括的主要内容有执行操作的事务标识、操作类型、更新前数据的旧值(插入操作此项为空)、更新后的数据值(删除操作此项为空)、更新日期和更新时间。一旦发生故障,DBMS 的恢复子系统利用日志文件撤销事务对数据库的改变,回退到事务的初始状态。因此,DBMS 利用日志文件来进行事务故障恢复和系统故障恢复,并可协助后备副本进行介质故障恢复。
登记日志文件时必须严格按照并发事务执行的时间次序来记录,且要先写日志文件后写数据库。
(4)数据库镜像。为了避免磁盘介质出现故障影响数据库的可用性,许多 DBMS 提供数据库镜像功能用于数据库恢复。需要说明的是,数据库镜像是通过复制数据实现的,但频繁地复制数据会降低系统的运行效果。因此实际应用中往往对关键的数据和日志文件镜像。
3.3 数据库的恢复
要使数据库在发生故障后能够恢复,必须建立冗余数据,在故障发生后利用这些冗余数据实施数据库恢复。建立冗余数据常用的技术是数据转储和建立日志文件。在一个数据库系统中,这两种方法一般是同时被采用的。
故障恢复有撤销事务(UNDO)和重做事务(REDO)两个操作:
撤销事务 (UNDO) 是将未完成的事务撤销,使数据库恢复到事务执行前的正确状态。
撤销事务的过程:反向扫描未完成的事务日志 (由后向前扫描),查找事务的更新操作;对该事务的更新操作执行逆操作,用日志文件记录中更新前的值写入数据库,插入的记录从数据库中删除,删除的记录重新插入数据库中;继续反向扫描日志文件,查找该事务的其他更新操作并执行逆操作直至事务开始标志。
重做事务 (REDO) 是将已经提交的事务重新执行。
重做事务的过程:从事务的开始标识起,正向扫描日志文件,重新执行日志文件登记的该事务对数据库的所有操作,直至事务结束标识。
对于不同的故障,采取不同的恢复策略。
1)事务故障恢复
事务故障是事务在运行至正常终止点(SUMIMIT 或 ROLLBACK)前终止,日志文件只有该事务的开始标识而没有结束标识。对这类故障的恢复是通过撤销(UNDO)产生故障的事务,使数据库恢复到该事务执行前的正确状态来完成的。事务恢复有如下四个步骤:
步骤1:反向扫描日志文件(即从最后向前扫描日志文件),查找该事务的更新操作。
步骤2:对事务的更新操作执行逆操作,也就是将日志记录更新前的值写入数据库。
步骤3:继续反向扫描日志文件,查找该事务的其他更新操作,并做同样的处理,直到事务的开始标志。
步骤4:继续处理下去,直到读到了此事务的开始标记,事务故障恢复完成了。
事务故障的恢复由系统自动完成,对用户是透明的。
2)系统故障的恢复
系统故障会使数据库的数据不一致,原因有两个:
一是未完成的事务对数据库的更新可能已写入数据库,撤销(UNDO)未完成的事务。
二是已提交的事务对数据库的更新可能还在缓冲区中没来得及写入数据库。因此恢复操作就是要撤销故障发生时未完成的事务,重做(REDO)已提交的事务。
系统故障的恢复是在系统重启之后自动执行的。
3)介质故障的恢复
介质故障时数据库遭到破坏,需要重装数据库,装载故障前最近一次的备份和故障前的日志文件副本,再按照系统故障的恢复过程执行撤销和重做来恢复。
介质故障的恢复需要 DBA 的参与,DBA 只需要重装最近转储的数据库副本和有关的各日志文件副本;然后执行系统提供的恢复命令;具体的恢复操作仍由 DBMS 完成。
4. 数据库的安全性与完整性
4.1 数据库的安全性
除了完整性约束提供保护意外引入的不一致性之外,数据库中存储的数据还要防止未经授权的访问和恶意的破坏或修改。
恶意访问的形式主要包括:未经授权读取数据(窃取信息);未经授权修改数据;未经授权破坏数据。
数据库安全性(databasesecurity)指保护数据库不受恶意访问。需要注意的是绝对杜绝对数据库的恶意滥用是不可能的,但是可以使那些企图在没有适当授权的情况下访问数据库的代价足够高,以阻止绝大多数这样的访问企图。为了保护数据库的安全,可以在以下五个层次上采取安全性措施:
数据库系统层次(database system)。数据库系统的某些用户获得的授权可能只允许他访问数据库中有限的部分,而另外一些用户获得的授权可能允许他提出查询,但不允许他修改数据。保证这样的授权限制不被违反是数据库系统的责任。
操作系统层次(operatingsystem)。不管数据库系统多安全,操作系统安全性方面的弱点总是可能成为对数据库进行未授权访问的一种手段。
网络层次(network)。由于几乎所有的数据库系统都允许通过终端或网络进行远程访问,网络软件的软件层安全性和物理安全性一样重要,不管在因特网上还是在私有的网络内。
物理层次(physical)。计算机系统所位于的结点(一个或多个)必须在物理上受到保护,以防止入侵者强行闯入或暗中潜入。
人员层次(human)。对用户的授权必须格外小心,以减少授权用户接受贿赂或其他好处而给入侵者提供访问机会的可能性。
为了保证数据库安全,用户必须在上述所有层次上进行安全性维护。如果较低层次上(物理层次或人员层次)安全性存在缺陷,高层安全性措施即使很严格也可能被绕过。
数据库安全机制:用户标识与鉴别、访问控制(自主存取控制(授权和角色)、强制存取控制、基于角色的存取控制)、视图机制、数据加密、审计、备份和恢复、聚合、推理和多实例。
1)通过权限操作控制
通过 DBMA 提供的授权功能赋予用户在数据库各个部分上的几种形式的授权,其中包括:
read 授权允许读取数据,但不允许修改数据。
insert 授权允许插入新数据,但不允许修改已经存在的数据。
update 授权允许修改数据,但不允许删除数据。
delete 授权允许删除数据。
可以赋予用户获得上面的所有授权类型或其中一部分的组合,也可以根本不获得任何授权。除了以上几种对数据访问的授权外,用户还可以获得修改数据库模式的授权:
index 授权允许创建和删除索引。
resource 授权允许创建新关系。
alteration 授权允许添加或删除关系中的属性。
drop 授权允许删除关系。
drop 授权和 delete 授权的区别在于 delete 授权只允许对元组进行删除。如果用户删除了关系中的所有元组,关系仍然存在,只不过是空的。如果关系被删除,那么关系就不再存在了。系中的所有元组,关系仍然存在,只不过是空的。如果关系被删除,那么关系就不再存在了。可以通过 resource 授权来控制创建新关系的能力。具有 resource 授权的用户在创建新关系后自动获得该关系上的所有权限。
index 授权看起来似乎是不必要的,因为索引的创建和删除不会改变关系中的数据。事实上,索引是提高性能的一种结构。但是,索引也会消耗空间,并且所有数据库的修改都需要更新索引。如果 index 授权被授予所有用户,那么执行更新操作的用户倾向于删除索引,而提出查询的用户倾向于创建大量索引。为了使数据库管理员能够管理系统资源的使用,我们有必要将索引的创建作为一种权限来看待。
最大的授权形式是给数据库管理员的。数据库管理员可以给新用户授权,可以重构数据库,等等。这一授权形式类似于操作系统中提供给超级用户或操作员的权限。
2)通过视图控制权限
视图是给用户提供个性化数据库模型的一种手段,而且可以隐藏用户不需要看见的数据。视图隐藏数据的能力既可以用于简化系统的使用,又可以用于实现安全性。由于视图只允许用户关注那些感兴趣的数据,它简化了系统的使用。尽管用户可能不被允许直接访问某个关系,但用户可能被允许通过一个视图访问该关系的一部分。因此,关系级的安全性和视图级的安全性可以结合起来,用于限制用户只能访问所需数据。
3)注意权限的授予
获得了某种形式授权的用户可能被允许将此授权传递给其他用户。但是,我们对于授权可能会在用户间怎样传递必须格外小心,以保证这样的授权在未来的某个时候可以被收回。
4)通过角色控制
考虑一个有很多出纳的银行。每一个出纳必须对同一组关系具有同种类型的权限。无论何时指定一个新的出纳,他都必须被单独授予所有这些授权。一个更好的机制是指明所有出纳应该有的授权,并单独标示出哪些数据库用户是出纳。系统可以用这两条信息来确定每一个有出纳身份的人的权限。当一个人被新雇佣为出纳时,必须给他分配一个用户标识符,并且必须将他标示为一个出纳,而不需要重新单独给予出纳权限。
在数据库中建立一个角色集,和授予每一个单个用户一样,可将权限授予角色。分配给每个数据库用户一些他(或她)有权扮演的角色(也可能是空的)。
5)通过审计追踪控制
很多安全的数据库应用软件需要维护审计追踪(audittrail)。审计追踪是一个对数据库所有更改(插入/删除/更新)的日志,还包括一些其他信息,如哪个用户执行了更改和什么时候执行的更改等。
可以在关系更新操作上定义适当的触发器来建立一个审计追踪(利用标示用户名和时间的系统变量)。然而,很多的数据库系统提供了内置机制来建立审计追踪,用起来会更加方便。
6)通过数据加密控制
目前数据加密仍是计算机系统对信息进行保护的一种最可靠的办法。它利用密码技术对信息进行加密,实现信息隐蔽,从而起到保护信息的安全的作用。对数据库中的数据进行加密,可以防止数据在存储和传输过程中失密。
按照作用的不同,数据加密技术可分为数据传输加密技术、数据存储加密技术、数据完整性的鉴别技术和密钥管理技术。
数据传输加密技术的目的是对传输中的数据流加密,通常有线路加密与端一端加密两种。线路加密侧重在线路上而不考虑信源与信宿,是对保密信息通过各线路采用不同的加密密钥提供安全保护。端一端加密指信息由发送端自动加密,并且由 TCP/IP 进行数据包封装,然后作为不可阅读和不可识别的数据穿过互联网,当这些信息到达目的地,将被自动重组、解密,从而成为可读的数据。
数据存储加密技术的目的是防止在存储环节上的数据失密,数据存储加密技术可分为密文存储和存取控制两种。前者一般是通过加密算法转换、附加密码、加密模块等方法实现;后者则是对用户资格、权限加以审查和限制,防止非法用户存取数据或合法用户越权存取数据。
数据完整性鉴别技术的目的是对介入信息传送、存取和处理的人的身份和相关数据内容进行验证,一般包括又令、密钥、身份、数据等项的鉴别。系统通过对比验证对象输入的特征值是否符合预先设定的参数,实现对数据的安全保护。
密钥管理技术包括密钥的产生、分配、保存、更换和销毁等各个环节上的保密措施。
4.2 数据库的完整性
数据库的完整性是指数据的正确性和相容性。如学生的性别只能是男或女, 百分制的成绩只能取0到100的整数值等。为防止错误数据进入数据库,DBMS提供了完整性约束机制,通过对数据库表结构进行约束,当对数据进行修改时由系统对修改数据进行完整性检查,将错误数据拒绝于数据库之外。
完整性约束条件作用的对象可以是表、行和列三种。
列级约束主要是对列的类型、取值范围、精度、非空值、值不可重复等的约束条件。- 行级约束是记录字段值之间联系的约束条件,如余额应该等于存入金额减去支出金额的差值。
表级约束是表的主码约束、表与表间的参照完整性约束、表中记录间的联系约束,如部门最高工资不能大于本部门平均工资的5倍。
列级约束、主码约束、参照完整性约束是在数据库定义过程中定义的,并和数据库定义的其他信息存储在数据字典中。标准SQL的DDL语言提供了这种功能,其他的相对复杂的约束需要编写触发器(trigger)程序实现。
在事务程序对数据库进行修改时,对于数据库定义的约束,由DBMS提供的完整性约束 机制来检查,如果不符合约束条件则拒绝修改并给出提示。对于触发器程序编制的约束,由触发器机制执行程序来实现约束。