【数据库系统 -8】数据库管理

数据库安全

数据库安全的高层观点:
在这里插入图片描述
数据库安全性常用的控制方法:

  • 用户标识与鉴定(最外层安全保护措施)
  • 存取控制(定义用户权限与合法权限检查)
    • 授权:GRANT <权限> ON <对象类型> <对象名> TO <用户> [WITH GRANT OPTION],执行该指令的可以是数据库管理员或数据库对象的创建者或拥有该权限的用户
    • 剥夺:REVOKE <权限> ON <对象类型> <对象名> FROM <用户> [CASCADE | RESTRICT]
  • 视图:把要保密的数据对无权存取这些数据的用户隐藏起来,对数据提供一定程度的安全保护
  • 审计
  • 数据加密

数据库完整性

数据库完整性包含了:

  • 数据的正确性:指数据是符合现实世界语义,反映了当前实际状况的
  • 数据的相容性:指数据库同一对象在不同关系表中的数据是符合逻辑的

在数据库刚开始,我们就已经介绍了数据库的完整性约束,参见:【数据库系统-2】关系数据库,在这里我们再细化一下:

对实体完整性约束:

  • 定义主码属性可以在列级定义,也可以在标记定义
  • 插入或对主码列进行更新操作时,需要检查主码值是否唯一,如果不唯一则拒绝插入或修改;检查主码的各个属性是否为空,只要有一个为空就拒绝插入或修改

对参照完整性约束:

  • 对被参照表和参照表进行增删改操作时有可能破坏参照完整性,比如在A表中增加一个元组,修改A表中的一个元组,在B表中修改一个元组,在B表中删除一个元组。
  • 如果检测到破坏参照完整性约束,可以有几种处理:
    • 拒绝执行(默认)
    • 级联:当删除或修改被参照表的一个元组造成了与参照表的不一致,则删除或修改参照表中的所有造成不一致的元组
    • 设置为NULL:当删除或修改被参照表的一个元组时造成了不一致,则将参照表中的所有造成不一致的元组的对应属性设置为空值

对于用户自定义的完整性约束:

  • 用户定义的完整性是:针对某一具体应用的数据必须满足的语义要求
  • 关系数据库管理系统提供了定义和检验用户定义完整性的机制,不必由应用程序承担
  • 比如NOT NULL、UNIQUE、CHECK都可以用来进行自定义约束

数据库并发控制

事务

事务是用户定义的一个数据库操作序列,这些操作要么全做,要么全不做,是一个不可分割的工作单位,是恢复和并发控制的基本单位。

定义方式:

BEGIN TRANSACTION
	sql1...
	sql2...
	...
COMMIT (ROLLBACK)

对于COMMIT:事务中所有对数据库的更新写回到磁盘上的物理数据库中
对于ROLLBACK:系统将事务中对数据库的所有已完成的操作全部撤销

ACID属性:

  • 原子性(Atomicity)
    事务中包括的诸操作要么都做,要么都不做
  • 一致性(Consistency)
    数据库中只包含成功事务提交的结果
  • 隔离性(Isolation)
    一个事务的执行不能被其他事务干扰
  • 持续性(Durability )
    一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。
并发控制概述

多用户数据库系统指的是允许多个用户同时使用的数据库系统,例如12306,携程等等,多用户数据库系统的特点就是在同一时刻并发运行的事务数可达成百上千个。

多事务的处理机执行一般有以下的几种方式:

  • 事务串行执行:每个时刻只有一个事务运行,其他事务必须等到这个事务结束以后方能运行,这种方式不能充分利用系统资源,发挥数据库共享资源的特点
  • 交叉并发执行:单处理机系统中,事务的并行执行是这些并行事务的并行操作轮流交叉运行。要认识到单处理机系统中的并行事务并没有真正地并行运行,但能够减少处理机的空闲时间,提高系统的效率
  • 同时并发执行:多处理机系统中,每个处理机可以运行一个事务,多个处理机可以同时运行多个事务,实现多个事务真正的并行运行

这里讨论的并发控制均是基于第二种并发方式——交叉并发执行。之所以要并发控制,是因为我们要维护数据库的稳定性。一般来讲,多事务执行,OS课上讲的那些问题就都有可能会出现,诸如读后写造成的不一致的问题。在数据库的并发控制中,并发操作可能带来以下问题:

  • 丢失修改:两个事务T1和T2读入同一数据并修改,T2的提交结果破坏了T1提交的结果,导致T1的修改被丢失
  • 不可重复读:不可重复读是指事务T1读取数据后,事务T2执行更新操作,使T1无法再现前一次读取结果。事务T1读取某一数据后,事务T2对其做了修改,或事务T2删除了其中部分记录,或事务T2插入了一些记录,当事务T1再次读该数据时,得到与前一次不同的值。
  • 读脏数据:事务T1修改某一数据,并将其写回磁盘;事务T2读取同一数据后,T1由于某种原因被撤销;这时T1已修改过的数据恢复原值,T2读到的数据就与数据库中的数据不一致;T2读到的数据就为“脏”数据,即不正确的数据。

并发控制就是要用正确的方式调度并发操作,使一个用户事务的执行不受其他事务的干扰,从而避免造成数据的不一致性,涉及到OS里面一些调度的思想,但也还行。并发控制的主要技术有:

  • 封锁
  • 时间戳
  • 乐观控制法
  • 多版本并发控制
封锁

封锁就是事务T在对某个数据对象(例如表、记录等)操作之前,先向系统发出请求,对其加锁。加锁后事务T就对该数据对象有了一定的控制,在事务T释放它的锁之前,其它的事务不能更新此数据对象。基本的封锁类型有排他锁(X锁)和共享锁(S锁)。

X锁

X锁也称为写锁。若事务T对数据对象A加上X锁,则只允许T读取和修改A,其它任何事务都不能再对A加任何类型的锁,直到T释放A上的锁,保证其他事务在T释放A上的锁之前不能再读取和修改A。

S锁

S锁也称为读锁。若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A其它事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。S锁保证其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。

下面是一些例子
(1)使用封锁机制解决丢失修改问题
在这里插入图片描述
T1在对A进行修改之前加了X锁,这时如果T2也请求修改A,加X锁的时候会被阻塞,只有当T1处理完,释放X锁,T2才能获得X锁,对A进行修改。这样就避免了丢失修改。

(2)使用封锁机制解决读取脏数据问题
在这里插入图片描述
T1再对A进行修改之前,加上X锁,这个时候T2请求读A,加S锁被阻塞,只有当T1回滚释放X锁之后,T2才能获得S锁,对A进行读,这就避免了脏数据。

(3)使用封锁机制解决不可重复读问题
在这里插入图片描述
T1请求读取A和B,对A和B分别加S锁,当T2请求修改B,加X锁时被阻塞,只有当T1完成校验,释放S锁后,T2才能获得X锁完成接下去的工作。这样就解决了不可重复读问题。

总结一下:

  • 加了X锁就不能再加S锁,加了S锁就不能再加X锁,加了S锁可以再加S锁,加了X锁不可以再加X锁
  • X锁允许当前事务读取和修改A,S锁只允许当前事务读取A
活锁和死锁
活锁

事务T1封锁了数据R,事务T2请求封锁R,于是T2等待;T3也请求封锁R,当T1释放了R上的封锁之后,系统首先批准了T3的请求,T2仍然等待;T4又请求封锁R,当T3释放了R上的封锁之后,系统又批准了T4的请求…这样,T2虽然没有处于忙等状态,但就是一直得不到资源,这就是活锁发生时的情形。时空图如下:
在这里插入图片描述
如何避免活锁产生?
采用先来先服务策略:当多个事务请求封锁同一数据对象时,按请求封锁的先后次序对这些事务排队,该数据对象上的锁一旦释放,首先批准申请队列中第一个事务获得锁。(数据结构:优先队列)

死锁

事务T1封锁了数据R1,T2封锁了数据R2,T1又请求封锁R2,因T2已封锁了R2,于是T1等待T2释放R2上的锁;接着T2又申请封锁R1,因T1已封锁了R1,T2也只能等待T1释放R1上的锁。这样T1在等待T2,而T2又在等待T1,T1和T2两个事务永远不能结束,形成死锁。
在这里插入图片描述
如何解决死锁?OS告诉我们可以从三个方面入手:检测死锁、避免死锁、解除死锁。对数据库的并发控制也一样:

  • 死锁的预防:
  1. 要求每个事务必须一次将所有要使用的数据全部加锁,否则就不能继续执行
  2. 顺序封锁法是预先对数据对象规定一个封锁顺序,所有事务都按这个顺序实行封锁
  • 死锁的检测:
  1. 超时法:如果一个事务的等待时间超过了规定的时限,就认为发生了死锁。这种方法实现起来简单,但是有可能产生误判,也有可能无法及时发现死锁(取决于超时时间设置为多长)。
  2. 等待图法: 事务等待图是一个有向图G=(T,U),T为结点的集合,每个结点表示正运行的事务;U为边的集合,每条边表示事务等待的情况;若T1等待T2,则T1,T2之间划一条有向边,从T1指向T2。如果图中存在回路,则表示系统中出现了死锁。
  • 死锁的解除:选择一个处理死锁代价最小的事务,将其撤消,则此事务持有的所有的锁都被释放,其它事务能继续运行下去。
并发调度的可串行性

上面我们讲丢失修改、不可重复读、读取脏数据的封锁策略,我们说封锁后得到的结果是正确的。这个正确是相对于什么说的呢?显然,如果一个并行的程序,其最终结果等价于串行执行的结果,那么这个并行调度就是可行的,称为可串行化调度

  • 可串行化调度:多个事务的并发执行是正确的,当且仅当其结果与按某一次序串行地执行这些事务时的结果相同
  • 可串行性:是并发事务正确调度的准则,一个给定的并发调度,当且仅当它是可串行化的,才认为是正确调度
冲突可串行化调度

冲突可串行化是比可串行化更严格的条件,首先我们要认识一下冲突操作。冲突操作指的是:不同事务同一数据读写操作和写写操作。(容易理解读读操作不会冲突)

不同事务的冲突操作同一事务的两个操作是不能交换的。对于Ri(x)和Wj(x),若改变两者的次序,则事务Ti看到的数据库状态就发生了改变,自然会影响到事务Ti后面的行为。对于Wi(x)和Wj(x),改变二者的次序也会影响数据库的状态,x的值由等于Tj的结果变成了等于Ti的结果。

冲突可串行化:一个调度Sc在保证冲突操作的次序不变的情况下,通过交换两个事务不冲突操作的次序得到另一个调度Sc’,如果Sc’是串行的,称调度Sc是冲突可串行化的调度。

若一个调度是冲突可串行化,则一定是可串行化的调度。但是可串行化的调度,不一定冲突可串行化。

举个例子来讲,现有调度:
在这里插入图片描述

Sc2等价于一个串行调度T1,T2。所以Sc1是冲突可串行化的调度。

两段锁协议

数据库管理系统普遍采用两段锁协议的方法实现并发调度的可串行性,从而保证调度的正确性。两段锁协议指的是所有事务必须分两个阶段对数据项加锁和解锁 。

  • 在对任何数据进行读、写操作之前,事务首先要获得对该数据的封锁
  • 在释放一个封锁之后,事务不再申请和获得任何其他封锁

两段锁协议下,事务分为两个阶段:

  • 扩展阶段(获得封锁):事务可以申请获得任何数据项上的任何类型的锁,但是不能释放任何锁
  • 收缩阶段(释放封锁):事务可以释放任何数据项上的任何类型的锁,但是不能再申请任何锁

下图是一个示意:
在这里插入图片描述

封锁粒度

封锁粒度指的就是封锁对象的大小,封锁的对象可包括逻辑单元和物理单元:

  • 逻辑单元:如属性值、属性值的集合、元组、关系、索引项、整个索引、整个数据库等
  • 物理单元:如页(数据页或索引页)、物理记录等

一般来讲,

  • 封锁的粒度越大,数据库所能够封锁的数据单元就越少,并发度就越小,系统开销也越小
  • 封锁的粒度越小,并发度较高,但系统开销也就越大

三级粒度树:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值