本章概要

  • 数据库保护概况
  • 数据库安全性
  • 数据库完整性
  • 故障恢复
  • 并发控制

数据库保护概况

数据库破坏类型以及对应的保护措施

1.非法用户:未经授权而恶意访问的,修改甚至破坏数据库的用户,包括越权访问用户

保护:针对非法用户,采用权限机制保护数据的安全

对应数据库功能中的安全性

2.各种故障:各种硬件故障、软件系统与应用软件的错误、用户失误等不可避免,这些故障轻的会导致运行事务的非正常结束,影响数据的正确性,严重的会破坏数据库,使数据库中的数据部分或全部丢失。

保护:提供故障恢复能力

3.对应数据库功能中的故障恢复

非法数据:指那些不符合规定或不符合语义要求的无效数据,一般由用户的误操作产生。

保护:利用完整性约束防止非法数据进入数据库

4.多用户并发访问:指那些不符合规定或不符合语义要求的无效数据,一般由用户的误操作产生。

保护:提供并发控制机制

对应数据库功能中的并发访问

回顾:DBMS的基本功能

  1. 数据的独立性
  2. 数据的安全性
  3. 数据的完整性
  4. 并发访问
  5. 故障恢复

其中数据的安全性,并发访问和故障恢复都是针对数据库的保护来实现的

数据库的安全性

数据库的特点是数据可以共享

数据的共享必然带来数据的安全性问题

数据库安全性的定义:数据库的安全性(Security)是指保护数据库,防止不合法的使用,以免数据的泄密、更改或破坏。

数据库的安全性控制

1.用户识别与鉴别:系统提供的最外层的安全保护措施

2.存取控制:分为两个部分,一个是定义用户权限,另一个是合法权限检查,用户权限定义和合法权限检查机制一起组成了DBMS的安全子系统

常见的存取控制方法:

自主存取控制:用户对不同的数据对象有不同的存取权限,不同用户对同一对象有不同权限。

强制存取控制:每一数据对象标以一定密级,每一用户对应某一级别的许可证,只有合法许可证的用户才可以存取某一对象。

3.自主存取权限DAC

自主存取权限有两个要素组成:1.数据对象2.操作类型

通过:SQL的GRANT和REVOKE语句来实现

1
2
3
4
GRANT <权限> [,<权限>] 
[on <对象类型><对象名>]
TO <用户>,[,<用户>]…
[WITH GRANT OPTION]

image-20230618145004749

拥有发出GRANT权限的:1.DBA 2.数据库对象创建者DBO 3.拥有该权限的用户

接收权限的用户:1.一个或者多个具体的用户2.PUBLIC

授予的权限可以由DBA或者其他授权者用REVOKE语句收回

1
2
3
REVOKE <权限> [,<权限>] 
[on <对象类型><对象名>]
FROM <用户>,[,<用户>]…

image-20230618145033604

SQL授权机制小结

image-20230618145333440

创建数据库模式的权限

1
2
CREATE USER <username>
[WITH] [DBA | RESOURCE | CONNECT]

image-20230618145605821

数据库角色

数据库角色:被命名的一组与数据库操作相关的权限。

角色的创建

1
create role <角色名>

给角色授权

1
2
GRANT <权限> [,<权限>]... ON <对象类型>对象名 TO
<角色> [,<角色>]...

对角色授权一个表中某个属性的权限:

例:

image-20230618150109903

本题答案是C

1
GRANT UPDATE(GRADE) ON SC TO ZHAO

角色权限的收回

1
2
REVOKE <权限> [,<权限>]... ON <对象类型><对象名>
FROM <角色> [,<角色>]...

将一个角色授予其他的角色或用户

1
2
GRANT <角色1> [,<角色2>]... TO <角色3> [,<用户1>]...
[WITH ADMIN OPTION]

其中 with admin option是允许被授权的角色和用户继续授权给其他用户

题目

image-20230618151003546image-20230618151301157

image-20230618151345849

SQL SERVER 安全体系

image-20230618151533890

由上图的时候可知:SQL SERVER安全体系由三级组成:DBMS或者DB服务器,DB,语句与对象级

身份认证模式

SQL Server有两种身份验证模式:1.Windows验证模式和2.SQL Server验证模式

登陆用户 (DBMS登陆用户)

image-20230618153540414

有了登陆用户才能进入数据库

数据库用户 DB用户(user)

1.当登陆用户登录进去后,在被设置为某个数据库用户之前,可以用guest用户身份访问该数据库

2.用sa用户在需要访问的数据库下定义登陆用户,该用户默认为该数据库的DB

1
2
3
4
5
sp_adduser [ @loginame = ] ‘登录名
[ , [ @name_in_db = ] ‘访问数据库时用的名字’ ]
sp_adduser @loginame = 'wtest6',@name_in_db ='wtest6'
sp_helpuser
sp_dropuser 'wtest6'

数据库系统角色

image-20230618154256905

1
2
3
4
5
6
7
8
9
10
11
sp_addrole [ @rolename = ] ‘ 新角色名’  
[ , [ @ownername = ] ‘该角色所有者’ ]
sp_addrole 'Student','DBO'
--默认情况下,创建用户角色的用户为该角色的所有者。
-- 为角色增加成员用户:sp_addrolemember
sp_helpuser
sp_addrolemember 'Student', 'wtest6'
sp_droprolemember 'Student','wtest6'
-- 删除角色:sp_droprole
sp_droprole 'Student'
-- 查询角色信息:sp_helprole

SQL Server 语句授权

image-20230618161059885

SQL Server 对象授权

数据库的用户在对数据库操作之前还需要对其授予所要操作对象或命令的权限

image-20230618154947854

注意,对列的权限只有select 和 update

对象授权和语句授权的区别

乍一看感觉它们两个没啥区别,实际上,语句授权的权限是用户对数据库本身的操作,就像建表,创建视图等。而对象授权是用户对数据库中表的操作,就是增删改查

插播一个疑问

image-20230618164539355

image-20230618164628116

数据库安全的其他内容

总览

  1. 数据加密
  2. 审计跟踪
  3. 统计数据库安全

数据库的完整性

完整性的概念

数据的正确性:指数据时符合现实世界的语义,反应了当前实际状态的

数据的相容性:指数据库同一对象在不同关系表中的数据是符合逻辑的

数据完整性的目标:

防止数据库中存在不符合语义的数据,也就是防止数据库中存在不正确的数据
防范对象:不合语义的、不正确的数据

RBMS对数据完整性的支持

  1. 提供定义完整性约束条件的机制:包括实体完整性,参照完整性和用户自定义完整性,通过DDL定义
  2. 提供完整性的检查方法
  3. 违约处理:用户如果违背了完整性约束时,采取1.拒绝(NO ACTION) 2.级联(CASCADE)执行其他操作

完整性的约束类型

image-20230618165724244

静态完整性约束(状态约束)

隐式约束

  • 域约束
  • 主键约束
  • 唯一约束
  • 一般性约束(检查约束,断言)
  • 参照完整性

固有约束:关系模型的固有约束有:关系的属性不可分,即原子性

显示约束:隐式约束和固有约束是最基本的约束,但不能完全的描述现实的规定和约束,特别是与具体的应用有关的约束,这就需要第三种静态约束来完成

完整性约束的定义

固有约束:无需定义

隐式约束:由开发人员或者DBA利用DDL语言定义

显示约束:有三种的可选的定义方式:即过程化定义,断言,触发器

动态约束过程化定义和触发器 (因为这两种方法都可以得到改变前后的数据,以便于比较决定是否允许这种数据状态的改变)

过程化定义:由程序员编写一个过程函数加入到应用程序中

断言

概念: 数据库状态应该满足的逻辑条件

方法:将定义与验证(完整性控制系统ICS)分开,定义采用断言定义语言ASL

1
2
3
4
5
6
7
8
-- 例:定义触发器base_trigger检验员工的工资不能高于部门经理
create trigger base_trigger on salary for Insert,Update AS
if ((Select base from inserted)>(Select s.base from salary s,
person p,inserted i where i.p_no=p.p_no and
s.p_no=p.p_boss))
begin print '基本工资过高!' ROLLBACK TRANSACTION
RETURN end
RETURN

完整性约束的验证与实施

问题:约束定义后,只是由DBMS存放到约束库中,何时起作用?

固有约束的验证: 由DBMS自动完成

隐式约束:当数据更新时,由DBMS按相应约束条件自动完成

显示约束

  1. 过程方式的定义约束仍需要开发人员编写过程

  2. 断言方式定义的约束由DBMSICS负责验证

  3. 触发器方式定义的约束由DBMS负责完成

动态约束

检查约束:同一时间两个属性的取值是否满足约束

动态约束:不同时间点同一个属性的取值是否满足约束

数据库的故障恢复技术

事务的管理概况

事务的概念:事务是构成单一逻辑工作单元的操作集合,DBS必须保证事务正确完整的执行

例如:从账户A转一笔款(90元)到账户B。其中有下列步骤:
read(A); A:=A-90; write(A); read(B); B:=B+90;write(B).
这所有操作应视为一个整体,要么全部完成,要么全部不做,决不允许只做一半操作。针对此类工作特点,引入”事务”(Transaction)概念。

事务的组成以及执行:事务时DBMS的最小执行单位,由有限的数据库操作序列组成,也是最小的故障恢复单位并发控制单位

对数据库的操作必须自成/组合为一个事务单位,以事务为最小的单位执行之;在并发执行时,亦是以事务为单位进行;在事务不完整、需要恢复数据时,仍然是以事务为单位进行恢复

并发访问数据库,故障恢复等数据库技术涉及的数据库状态常常从事务这样的粒度出发

COMMIT 和 ROLLBACK

如果事务执行成功,DBMS应该保证事务中的所有步骤对数据的更新有效,若事务失败,DBMS应该撤销已经执行的步骤对数据的更新

一个事务由应用程序中的一组操作序列组成,在程序中,事务以BEGIN TRANSACTION开始,以COMMIT语句或者ROLLBACK语句结束

Commit表示事务执行成功地结束(提交)。
Rollback表示事务执行不成功(回退),DBMS将事务中对数据库的所有已完成的更新操作全部撤销,数据库应回退到该事务开始时的状态。

事务状态变迁

事务的状态由:活动状态,操作结束,事务提交,事务结束,事务失败, 回退

image-20230622110110384

事务的ACID准则 重点!!!!

原子性(Atomicity):一个事务对数据库的所有操作是一个整体,要么成功执行,要么都不执行(Nothing or All)。保证原子性由DBMS的事务管理器(Transaction Manager)负责,”提交(Commit)“和””回退(Rollback)“操作是其中的关键

一致性(Consistency):在无其它事务并发执行时,单独运行的事务应保证DB从一个一致状态转到另一个一致状态。但事务管理器无法保证事务内的一致性,例如:如果系统用户在设计转帐事务时,只编写了第一步代码(从A账户中转出90元),而没有编写了
第二步代码,这样造成的数据库不一致,需由系统用户负责。

隔离性(Isolation):DBMS为改善性能要交错执行几个事务的操作,但要求这些并发执行的事务,对用户而言象是单独执行一样。该特性由并发控制负责

持久性(Durability):一旦DBMS告诉用户事务成功执行,其对数据库的影响应是持久的,即使在事务导致的变化写盘之前,系统崩溃了仍应如此。该特性和第一个特性(原子性)由故障恢复通过日
志负责。

DBMS中的事务控制

DBMS对事物的控制由两种方法:隐式的事务控制和显示的事务控制

隐式的事务控制:默认情况下,DBMS一般将一个数据库操作(如一条SQL语句)当作一个事务来控制执行。

显示的事务控制:对涉及多步操作的(一般含多条SQL语句)、有事务特点的工作,则需要人为地、显式地将这些操作”界定”,组合成一个事务交给DBMS控制执行。

1
2
3
4
-- SQL SERVER提供的界定事务的常用语句: 
BEGIN { TRANSACTION | TRAN | WORK } [事务名]
ROLLBACK { TRANSACTION | TRAN | WORK } [ 事务名]
COMMIT { TRANSACTION | TRAN | WORK } [事务名]

事务管理的内容

引起事务不完全的三个故障原因

  • 由于出现异常,中途中止或不成功退出;
  • 可能因电源等故障,系统崩溃;
  • 遇到如不能访盘等异常状态而中止。

ACID准则不容破坏:不仅在系统正常如此,在系统故障时也应该如此,在单个事务执行时如此,在事务并发执行时也应该如此

  • 故障恢复:保证事务在故障时满足ACID 准则的技术;
  • 并发控制:保证事务在并发执行时满足ACID准则的技术;
  • 事务管理:故障恢复和并发控制的合称。

故障恢复的导论

(1) 典型的故障恢复策略

1.DBS运行时:各种故障—>数据丢失—>数据恢复

2.典型的恢复策略

日常工作的两件事:转储 和 建立日志

转储:周期地对整个数据库进行拷贝,转储到另一个磁盘或磁带上 - 数据库备份
建立日志数据库:记录事务的开始、结束。记录事务对数据库的每一次增、删、改


3.一旦发生数据库故障,分两种情况处理

  • 遇到灾难性故障:使用数据库备份,再利用日志
  • 未遇到物理破坏,但是数据库一致性被破坏:仅使用日志库

故障恢复导论

image-20230622113606693

下面就围绕着几个故障恢复技术进行展开

单纯以后备副本为基础的恢复技术

  1. 周期性转储到数据库到磁带上,备份时间一般在夜间,周末
  2. 出现故障的时候,取离故障点最近的后备副本来恢复
  3. 缺点是:丢失数据

image-20230622141735069

对该技术的改进:增量转储

增量转储:在某个时间转储修改过的物理块,减少转储是加密,存储空间和数据丢失

技术特点:实现简单,缺点就是不能恢复尽可能近一点的一致状态,只适用于小型或者不重要的DBS。

image-20230622142108994

起始增量转储有点像git机制中的 git add. git commit 每次只增加仓库的增量,而不是把整个仓库都重新提交,大大提高了速度。

从这个图中可以看出,故障点发生后,如果使用增量转储,只损失这一段的数据,而如果不采用,则损失,这一段的数据。

以后备副本和日志为基础的恢复技术

首先要清楚几个名词:

日志(LOG): 供恢复用的DB运行情况的记录,其内容由 前像,后像和事务状态(各种事务表)

前像(BI): 事务所更新的数据所在的物理块在更新前的映像(Before Image 简写 BI)

当撤销(Undo)更新,使DB恢复到更新前的状态,用前像覆盖事务所做的更新

后像(BI):所涉及的物理块更新后的映像,如重做(Redo)更新,可以使得DB恢复到更新后的状态,即用后像覆盖所在的物理块,就能使数据库恢复到更新后的状态

image-20230622144000957

故障事务处理的依据:事务时已提交还是未提交

系统处理:事务一旦开始,即记入日志,并且跟踪事务的两种状态 一是活动的状态,二是提交状态(区分事务是否提交)

恢复方法:故障排除后,先取最近副本,然后根据日志中的事务是否提交作相应处理。对未提交事务,应用前像回退;对已提交事务一般用后像重做

基于多副本的数据库恢复技术

方法:利用多副本互为备份,恢复

操作系统级和DBMS级

image-20230622145450274

基于数据库级的恢复技术

  1. DBMS级的可靠性技术:数据库复制(Replication)、数据库镜像、日志镜像。

  2. 数据复制技术:多个场地保存多个数据库副本,各个场地的用户可以并发地存取不用的数据库副本,通过分布式的复制服务器实现

  3. 数据复制要求:DBMS须要采取一定的手段用户对DB的修改能及时的反映到所有副本上

  4. 数据复制优点

    (1).当一个用户为修改数据加锁的时候,其他用户可以访问数据库副本

    (2).当数据库出现故障的时候,系统可以用副本进行联机恢复,恢复过程中,用户可以继续访问副本而不用中断应用

数据库复制

数据库复制的三种方式: 对等复制,主从复制,级联复制

  1. 对等复制:是理想的复制方式。各场地DB地位平等,可互相复制数据。用户可在任一场地读取/更新公共数据,DBMS应将更新数据复制到所有副本

  2. 主从复制:数据只能从主DB复制到从DB,更新数据也只能在主场地进行,从场地供用户读取数据,当主场地出现故障时,更新数据的应用可以转到某一从场地

    image-20230622150914684

  3. 级联复制:从主场地复制来的数据又从该场地复制到其他场地,级联复制可以平衡当前数据需求对网络流量的压力

    image-20230622151401202

数据库镜像

image-20230622151949104

数据库日志

日志记录(LOG):DB恢复必须的数据

日志以及DB的存放:日志丢失,DB就无法恢复,因此日志和DB要放在不同的分区(磁盘,磁盘副带)image-20230622152146175

日志的基本内容

  1. 活动事务表(ATL):记录正在执行,尚未提交的事务标识符(TID)
  2. 提交事务表(CTL):记录已经提交事务的标识符
  3. 前像文件:可看成堆(Heap)文件,每个物理块有块标识符(Block Identifier, BID)
  4. 后像文件:结构类似前像文件,但其记录的是后像。

BI 和 AI 在 数据库恢复中的作用

  • 如果事务未提交(没有commit, Tid没有写入CTL):
    用BI恢复 = undo。
  • 如果事务已提交(已经commit, Tid写入了CTL):
    用AI恢复 = redo

数据库恢复后对日志的处理

image-20230622153319703

总之就是:前像删除,后像自由选择

DBMS围绕更新事务的工作

  1. 提交规则

该规则要求:后像应该在提交前写入DB或者日志

这个是ACID中的持久性的要求,提交规则不要求后向一定在提交前写入DB,写入日志中亦可,即:如后像已写入日志,即使未写入DB或未完全写入DB,事务仍可提交,待事务提交后再继续写入DB。如此期间出现故障,可用日志的后像重做;其它事务可从缓冲区(未写入DB前更新内容仍在缓冲区)访问更新后的内容。

  1. 先写后记规则

如后像在事务提交前写入DB,需先将前像写入日志,以便事务失败后,撤销事务所做的更新。

故障类型以及恢复对策

事务的成功执行与结束: 一个事务以BEGIN TRANSACTION开始,以ROLLBACK的语句成功执行结束

提交点:COMMIT 建立了一个提交点(commit Point)

在商用DBMS产品中也叫同步点(Syncpoint)。提交点标志着逻辑工作单元的结束,要求DB处于一致状态。

可恢复的故障

  • 事务故障
  • 系统故障
  • 介质故障

事务故障

事务失效的原因

事务无法执行而中止。
用户主动撤销事务。
因系统调度差错而中止。
因电源故障而中止。
因介质故障而中止。

事务故障的恢复措施:

  1. 丢弃该事务的消息队列
  2. 扫描日志,撤销所有不可靠的修改
  3. 从ATL删除该事务的TID,释放该事务所占的资源

系统故障

系统故障也称为软故障

  1. 掉电
  2. 除了DB存储介质故障之外的软硬件故障

系统失效的恢复措施

1.重新启动OS和DBMS

2.恢复DB到一致的状态(未提交事务进行undo,对已提交的事务进行redo)

磁盘故障

更换或者修复磁盘后,重新启动系统后需要用数据库后备副本恢复数据库,再装入日志副本,重做已经提交的事务

恢复措施的改进

image-20230622163114838

数据库系统中的并发

基于锁的并发控制协议

封锁技术:

锁(Lock)是一个与数据项相关的变量,对可能应用于该数据项上的操作而言,锁描述了该数据项的状态。

加锁协议类型:

  • X锁 (排他锁)
  • 两阶段加锁协议(2PL协议)
  • (S,X)锁
  • (S,U,X)锁
  • 多粒度加锁或封锁

X锁枷锁协议

X锁协议:该协议中,只有一种锁,即X(eXclusive)锁,亦称排他/独占锁,既可用于读操作,亦可用于写操作。一个事务对某个数据对象加排他锁后,其它事务就不能对该数据对象加锁,必须等到该数据对象上的X锁被“解锁”(Unlock),或”释放”后,才可能再加锁。

相容矩阵:加锁协议可用相容矩阵描述。所谓相容矩阵,是说明锁请求在什么情况下可获准或被拒绝。

如果获准,即已有锁与申请锁相容;

如果被拒绝,即已有锁与申请锁”冲突”或”相斥”

Y:YES N:NO NL:NO LOCKimage-20230622190350335

X锁的作用:

能够消除“写-写”、“写-读”、“读-写”冲突,因为,不论是“写”或“读”都要加X锁,加了X锁后,就排斥了对同一对象的任何操作,甚至包括不冲突的“读-读”操作。

但X锁协议可能引起“级联回退” 现象。即一事物还未结束,就把锁释放了,其中又由于其他原因,该事物需要回退,为了避免其他事物读到“脏”数据,要求读了该事物更新数据的其他事物也要回退

级联回退可以见下图

image-20230622190616961

从图中可以看出,事件T1中A RollBack后,在此期间所有访问过A的事件T2,T3都需要RollBack

加锁协议补丁1(Path)

为避免级联回退,要求不管是写操作锁还是读操作锁都应保持到事务结束(End of Transaction, EOT)才释放。该补丁对其后的加锁协议也适用。

两阶段加锁协议 (S,X)锁

两阶段事务:在一个事务中,如加锁都在所有释放锁之前,则此事务为两阶段事务。其中的加锁限制称为两阶段加锁协议( Two-Phase Locking protocol, 2PL协议)

(1)每个事务分为两阶段,前阶段加锁而不解锁(扩展阶段),后阶段解锁而不加锁(收缩阶段

(2) 两阶段事务中,一旦开始解锁,就不能再对任何数据对象加锁。

合式事务:一个事务如果遵守先加锁,后操作的原则,此事务即位合式事务

定理:如所有事务都是合式,两阶段的事务,则它们的任何调度都是可串行化的

(S,X)加锁协议

  1. S锁: 用于读操作
  2. X锁: 用于写操作

相容矩阵

与X锁协议比较,由于这里的S锁只用于读,故S锁与S锁是相容的。即:同一数据对象可允许多个事务并发读,这样比单一的X锁提高了并发度。

image-20230622191903936

活锁:

如一数据对象已被加S锁,其他事务要申请对它的X锁,需等待。若此时有其他事务申请对它的S锁,按相容矩阵,应可获准。如不断有事务对它申请S锁,以致该数据对象一直被S锁占据,而X锁的申请迟迟得不到获准,此现象称作活锁。

活锁类似操作系统中的饥饿

image-20230622192154063

加锁协议补丁2

  • 活锁虽不会导致“死等”,但对系统性能有不良影响。为避免活锁,在加锁协议中应规定“先申请先服务(First Come, First Served)”原则。
  • 说明:为保证可串行化和避免级联回退现象,(S,X)锁一般应保持到EOT才释放。该加锁协议繁简适当,有相当多的DBMS采用此协议。

(S,U,X)加锁协议

除了S,X锁以外,又增加了U锁

增加U锁的原因:事务在做更新时,一般分两个步骤:先读后写。即先读老内容,在内存中修改后;然后再写入修改后的内容。此过程中,除最后的写入阶段外,为保证需更新的数据对象仍可被其它事务访问,而新增此更新锁

U锁的使用以及作用:

事务要更新数据对象时,先申请该对象的U锁。数据对象加了U锁后,仍允许其他事务对它加S锁。在最后写入时,事务再申请将U锁升级为X锁。由于不必在事务执行的全过程中加X锁,可进一步提高并发度

相容矩阵如下:

image-20230622192925884

(S,U,X)协议遵守补丁1,2

  1. 保证可串行化和避免级联回退等现象,除U锁后来升级为X锁外,S、X锁一般应保持到EOT才释放。

    在(S, U, X)加锁协议中,为防止级联回退,S、U和X这三种锁是否都应保持到事务结束时才释放?为什么?

    答:S和X锁应保持到事务结束时才释放,但U锁则不必。因为U锁需要在事务内升级为X锁。

  2. 数据对象加了U锁后,其他事务可能连续不断地对它加S锁,但是U锁迟迟不能升级为X锁,为了避免这种活锁,要求也要遵循”先申请先服务”原则

多粒度加锁协议

在数据库中,一个数据对象的大小可以大到整个数据库、一页、一个表,也可以小到一行(即元组)。 对加锁来说,数据对象的大小即是加锁的粒度。

粒度、控制及并发度间关系:加锁单位愈大,加锁愈简单,但同时会降低并发度。反之,加锁单位越小,往往需要加很多的锁,所需的控制越复杂,不过并发度可提高。

并发度和加锁单位成反比!

实际需要:实际应用中,有时要访问大片数据,而有时只访问个别数据,为此,可提供多级加锁单位,根据应用需要加以选用,此即:多粒度加锁,它使得对包含有其它对象的对象加锁更加有效。

实际RDBMS做法:现代大型DBMS一般均支持多粒度加锁,而在微机DBMS中,并发度要求不高,一般以表作为加锁单位,此即:单粒度加锁(Single Granularity Locking)。

锁冲突检测问题(一)

image-20230622194307155

锁冲突检测问题(二)

如只有显式锁,锁的冲突较易发现;若有隐式锁,则检查冲突较复杂。

多粒度加锁下,要对某数据对象加锁时的锁冲突检测

所以多粒度加锁下,要对某数据对象加锁时的锁冲突进行检测

首先根据数据对象的大小关系,区分为祖先和子孙

  1. 检查本身,有无显示锁和本事务显示锁冲突
  2. 检查本事务的祖先,以防本事务的显示锁与其他事务的隐式锁冲突
  3. 检查本事务的子孙,以防本事务的隐式锁和其他事务的显示锁冲突

注意,祖先对应的时隐式锁,子孙对应的是显示锁

意向锁的提出:

为简化锁冲突的检测,多粒度加锁协议中,除S锁和X锁外,另外引入了三种意向锁

意向共享IS锁

加IS锁:一个事务要给一个数据对象加S锁,必须首先将其祖先加IS锁。也就是说,如果一个数据对象被加了IS锁,表示其某些子孙加了或准备加S锁。

IS锁冲突检测

image-20230622200501739

另外两个锁意向排他锁IX共享意向排他锁 SIX

共享意向排他锁 SIX:一个事务要读取整张表并修改其中某个元组,也就是说事务要整张表的S锁和IX锁,这两个锁冲突

多粒度加锁/解锁顺序

  1. 加锁时,必须对这个数据对象的所有祖先加相应的意向锁(IS锁),即:申请锁时,应按自上而下(从根到叶)的次序申请,以便及时发现冲突;
  2. 解锁时,应按自下而上(从叶到根)的次序进行,以免出现锁冲突。

死锁以及预防,检测,处理

死锁的定义:当事务出现循环等待时,如不加干预,则会一直等待下去,形成死锁(dead lock)

时间 事务T1 事物T2
t0 对A加X锁
t1 对B加X锁
t2 欲对B申请S锁
t3 等待 欲对A申请X锁
t4 等待

解决死锁的办法:

  1. 防止死锁
  2. 检测死锁,发现死锁后处理死锁

死锁的预防

方法:给每个事务一个优先级,并禁止低优先级的事务等待高优先级事务,或反之。而事务优先级的设定,是当事务开始执行时,给事务一个时间戳ts(Time Stamp)来完成。

时间戳:唯一的,随时间增长的整数

在这里需要强调一下:

每个事务在开始执行的时候给予一个时间戳,时间戳会一直增长下去,并不是不变的,所以时间戳越大,说明事务执行顺序的越靠前,事务越老,事务的优先级越高,

事务的优先级时间戳越前,事务的优先级越高,也就是说越老的事务,其优先级越高。

示例:有两个事务TA和TB,如ts(TA)>ts(TB),
则表示TA早于TB, TA优先级高。

那么应该如何通过优先级来预防死锁呢?

基本思想:就是只允许事务间的单项等待,而不允许双向等待,即要么是年老(优先级高的)的事务等待年轻的事务(优先级低的),要么是年轻的事务等待年老的事务,这样事务的等待就不会出现死循环,也不会形成死锁

死锁的检测

检测死锁的方式:

  1. 超时法
  2. 等待图法

超时法

1)超时法
方法:如果一个事务等待锁的时间太长,超过事先设定的时限,则主观认定其处于循环等待中而撤销之(Rollback)。
说明:

  1. 很晚才能发现死锁;
  2. 可能存在误判;
  3. 超时时间设置问题。设置越小,误判机会越大;设置太大,则发现死锁的滞后时间会过长。

等待图法

等待图:是一个有向图G=(W,U),W是当前运行事务的集合,U是边的集合,U={(Ti,Tj) | Ti等待Tj, i≠j}。
等待图的维护:当某个锁请求加入队列时,锁管理器会向图中增加一条边,而某个锁请求得到获准时,则它会从图中删除一条相应的边。
死锁检测方法:当且仅当等待图中出现回路时,死锁才发生。

检测改进:当运行事务较多时,维护等待图和检测回路开销较大。如每出现一个等待都要检测一次,虽然可及时发现死锁,但开销太大,影响系统性能。合理的方法是周期性进行死锁检测。

下面结合例子来具体说明一下等待图法:

image-20230622204757740

对于B,由于事务2在t2的时候先申请了X锁,所以当事务1在t4的时候对其申请S锁,就会在等待图上,画一个T4到T2的边

总之:对同一个资源来看后来申请锁的事务向之前申请锁的事务画出一条边

死锁的处理

处理思想:“杀死”事务,打破循环等待,解除死锁。
死锁处理的步骤:

  • 在循环等待的事务中,选一事务作为牺牲者;
  • 回退牺牲的事务,释放其获得的锁及其他资源;
  • 将释放的锁让给等待它的事务。

牺牲事务的选择标准:

  • 选择最迟交付的事务作为牺牲者;
  • 选择获得锁最少的事务作为牺牲者;
  • 选择回退代价最小的事务作为牺牲者