您好,欢迎来到飒榕旅游知识分享网。
搜索
您的当前位置:首页数据库并发控制

数据库并发控制

来源:飒榕旅游知识分享网
数据库是一个共享资源,可以提供多个用户使用。这些用户程序可以一个一个地串行执行, 每一个时刻惟独一个用户程序运行, 执行对数据库的存取, 其他用户程序必须等到这个用户程 序结束以后方能对数据库存取。但是如果一个用户程序涉及大量数据的输入/输出交换,则 数据库系统的大部份时间处于闲置状态。 因此, 为了充分利用数据库资源, 发挥数据库共享 资源的特点, 应该允许多个用户并行地存取数据库。 但这样就会产生多个用户程序并发存取 同一数据的情况, 若对并发操作不加控制就可能会存取和存储不正确的数据, 破坏数据库的 一致性, 所以数据库管理系统必须提供并发控制机制。 并发控制机制的好坏是衡量一个数据 库管理系统性能的重要标志之一。

DM 用封锁机制来解决并发问题。它可以保证任何时候都可以有多个正在运行的用户程序, 但是所实用户程序都在彼此彻底隔离的环境中运行。

一、 并发控制的豫备知识

(一) 并发控制概述

并发控制是以事务(transaction)为单位进行的。

1. 并发控制的单位 ――事务

事务是数据库的逻辑工作单位,它是用户定义的一组操作序列。一个事务可以是一组SQL 语句、一条 SQL 语句或者整个程序。

事务的开始和结束都可以由用户显示的控制, 如果用户没有显式地定义事务, 则由数据库系 统按缺省规定自动划分事务。

事务应该具有 4 种属性:原子性、一致性、隔离性和持久性。

(1)原子性

事务的原子性保证事务包含的一组更新操作是原子不可分的,也就是说这些操作是一个整 体, 对数据库而言全做或者全不做, 不能部份的完成。 这一性质即使在系统崩溃之后仍能得 到保证, 在系统崩溃之后将进行数据库恢复, 用来恢复和撤销系统崩溃处于活动状态的事务 对数据库的影响, 从而保证事务的原子性。 系统对磁盘上的任何实际数据的修改之前都会将 修改操作信息本身的信息记录到磁盘上。 当发生崩溃时, 系统能根据这些操作记录当时该事

务处于何种状态, 以此确定是撤销该事务所做出的所有修改操作, 还是将修改的操作重新执 行。

(2)一致性

一致性要求事务执行完成后, 将数据库从一个一致状态转变到另一个一致状态。它是一种以 一致性规则为基础的逻辑属性, 例如在转账的操作中, 各账户金额必须平衡, 这一条规则对 于程序员而言是一个强制的规定, 由此可见, 一致性与原子性是密切相关的。 事务的一致性 属性要求事务在并发执行的情况下事务的一致性仍然满足。它在逻辑上不是独立的, 它由事 务的隔离性来表示。

(3) 隔离性

隔离性意味着一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对 并发的其他事务是隔离的, 并发执行的各个事务之间不能互相干扰。 它要求即使有多个事务 并发执行,看上去每一个成功事务按串行调度执行一样。这一性质的另一种称法为可串行性, 也就是说系统允许的任何交织操作调度等价于一个串行调度。串行调度的意思是每次调度一 个事务,在一个事务的所有操作没有结束之前,此外的事务操作不能开始。由于性能原因, 我们需要进行交织操作的调度,但我们也希翼这些交织操作的调度的效果和某一个串行调度 是一致的。 DM 实现该机制是通过对事务的数据访问对象加适当的锁,从而排斥其他的事 务对同一数据库对象的并发操作。

(4)持久性

系统提供的持久性保证要求一旦事务提交, 那末对数据库所做的修改将是持久的, 无论发生 何种机器和系统故障都不应该对其有任何影响。例如,自动柜员机( ATM)在向客户支付 一笔钱时, 就不用耽心丢失客户的取款记录。 事务的持久性保证事务对数据库的影响是持久 的,即使系统崩溃。正如在讲原子性时所提到的那样,系统通过做记录来提供这一保证。

DM 没有提供显式定义事务开始的语句,第一个可执行的SQL 语句(除 CONNECT 语句外) 隐含事务的开始, 但事务的结束可以由用户显式的控制。 在 DM 中以下几种情况都结束 (正 常,非正常)某一事务:

(1)当某一连接的属性设置为自动提交,每执行一条语句都会提交;

(2)遇到 COMMIT/ROLLBACK 语句,便提交/回滚一事务;

(3)当系统的 DDL 自动提交开关打开时(缺省为打开),遇到 DDL 语句则自动提交该 DDL 语句和以前的 DML 和 DDL 操作;

(4)事务所在的程序正常结束和用户退出;

(5)系统非正常终止时;

说明: DM 在配置文件中提供了 DDL 语句的自动提交开关 DDL_AUTO_COMMIT。 当此配 置项的值为 1 (缺省情况)时,所有 DDL 语句自动提交;当此配置项的值为 0 时,除 CREATEDATABASE、ALTERDATABASE 和 CREATESCHEMA 语句外的所有 DDL 语句 都不自动提交。

DM 中的一致性是以事务为基础的。 DM 通过提交和回滚分别用于将对数据库的修改永久化 和废除,但是无论是提交和回滚, DM 保证数据库在每一个事务开始前、结束后是一致的。为 了提高事务管理的灵便性, DM 提供了设置保存点(SAVEPOINT)语句和回滚到保存点语 句。 保存点提供了一种灵便的回滚, 事务在执行中可以回滚到某个保存点, 在该保存点以前 的操作有效,而以后的操作被回滚掉。

DM 中的事务同样具有上述 4 个属性:原子性、一致性、隔离性和持久性。

2. 并发操作与数据的不一致性

如果没有锁定且多个用户同时访问一个数据库,则当他们的事务同时使用相同的数据时可能 会发生问题,导致数据库中的数据的不一致性。

一个最常见的并发操作的例子是火车/飞机订票系统中的订票操作。例如,在该系统中的一 个活动序列:

① 甲售票员读出某航班的机票张数余额A,设 A=16;

② 乙售票员读出同一航班的机票张数余额A,也是 16;

③ 甲售票员卖出一张机票,修改机票张数余额A=A-1=15,把 A 写回数据库;

④ 乙售票员也卖出一张机票,修改机票张数余额A=A-1=15,把 A 写回数据库。

结果明明卖出两张机票,数据库中机票余额只减少 1。

这种情况称为数据库的不一致性。 这种不一致性是由甲、 乙两个售票员并发操作引起的。 在 并发操作情况下,对甲、 乙两个事务操作序列的调度是随机的。若按上面的调度序列行,甲 事务的修改就被丢失。这是由于第 4 步中乙事务修改 A 并写回覆盖了甲事务的修改。

并发操作带来的数据库不一致性可以分为四类: 丢失或者覆盖更新、 脏读、 不可重复读和幻像 读,上例只是并发问题的一种。

(1) 丢失或者覆盖更新(lost

update)

当两个或者多个事务选择同一数据, 并且基于最初选定的值更新该数据时, 会发生丢失更新问 题。 每一个事务都不知道其它事务的存在。 最后的更新将重写由其它事务所做的更新, 这将导 致数据丢失。 上面预定飞机票的例子就属于这种并发问题。事务 1 与事务 2 先后读入同一数 据 A=16,事务 1 执行 A-1,并将结果 A=15 写回,事务 2 执行 A-1,并将结果 A=15 写回。事 务 2 提交的结果覆盖了事务 1 对数据库的修改,从而使事务 1 对数据库的修改丢失了。

(2) 脏读

一个事务读取了另一个未提交的并行事务写的数据。当第二个事务选择其它事务正在更新的 行时, 会发生未确认的相关性问题。 第二个事务正在读取的数据还没有确认并且可能由更新 此行的事务所更改。换句话说,当事务 1 修改某一数据,并将其写回磁盘,事务2 读取同 一数据后,事务 1 由于某种原因被撤销,这时事务 1 已修改过的数据恢复原值,事务 2 读 到的数据就与数据库中的数据不一致,是不正确的数据,称为脏读。

例如,在下图中,事务 1 将 C 值修改为 200,事务 2 读到 C 为 200,而事务 1 由于某种原 因撤销,其修改作废, C 恢复原值 100,这时事务 2 读到的就是不正确的“脏“数据了。

(3) 不可重复读(nonrepeatable read)

一个事务重新读取前面读取过的数据, 发现该数据已经被另一个已提交的事务修改过。 即事 务 1 读取某一数据后,事务 2 对其做了修改,当事务 1 再次读数据时,得到的与第一次不 同的值。

例如,在下图中,事务 1 读取 B=100 进行运算,事务 2 读取同一数据 B,对其进行修改后 将 B=200 写回数据库。事务 1 为了对读取值校对重读 B,B 已为 200,与第一次读取值不 一致。

(4) 幻像读

如果一个事务在提交查询结果之前, 另一个事务可以更改该结果, 就会发生这种情况。 这句 话也可以这样解释,事务 1 按一定条件从数据库中读取某些数据记录后未提交查询结果, 事务 2 删除了其中部份记录,事务 1 再次按相同条件读取数据时,发现某些记录神奇地消 失了;或者事务 1 按一定条件从数据库中读取某些数据记录后未提交查询结果,事务2 插 入了一些记录,当事务 1 再次按相同条件读取数据时,发现多了一些记录。

产生上述四类数据不一致性的主要原因是并发操作破坏了事务的隔离性。并发控制就是要用 正确的方式调度并发操作, 使一个用户事务的执行不受其他事务的干扰, 从而避免造成数据 的不一致性。 3. 并发场景列举

结合 SQL 语句,列举各种并发情况(包括可能导致数据不一致性和对数据一致性不产生影 响的情况) 。A 表示某一条数据, b 和c 都表示满足某一个标准的两条或者多条数据, ^表示“非” 的意思,∈表示属于或者包含于的意思, 1 表示第一个事务, 2 表示第二个事务。

(二) 并发操作的调度

计算机系统对并行事务中并行操作的调度是随机的,而不同的调度可能会产生不同的结果, 那末哪个结果是正确的,哪个是不正确的呢?

如果一个事务运行过程中没有其他事务在同时运行, 也就是说没有受到其他事务的干扰, 那 么就可能认为该事务的运行结果是正常的或者预想的,因此将所有事务串行起来的调度策略 是正确的调度策略。 虽然以不同的顺序串行执行事务也可能会产生不同的结果, 但由于不会 将数据库置于不一致状态, 所以都可以认为是正确的。 由此可以得到如下结论: 几个事务的 并行执行是正确的, 当且仅当其结果与按某一次序串行地执行它们的结果相同。我们称这种

并行调度策略为可串行化(serializable)的调度。可串行性(serializability)是并行事务正 确性的惟一准则。

例如,现在有两个事务,分别包含下列操作: 事务 1:读 B;A=B+1;写回 A; 事务 2:读 A;B=A+1;写回 B;

假设 A 的初值为 10,B 的初值为 2。下图给出了对这两个事务的三种不同的调度策略, (a) 和(b)为两种不同的串行调度策略,虽然执行结果不同,但他们都是正确的调度。(c) 中两个事务是交织执行的,由于执行结果与(a)、(b)的结果都不同,所以是错误的调 度。(d)中的两个事务也是交织执行的,由于执行结果与串行调度1 (图(a))的执行结 果相同,所以是正确的调度。

为了保证并行操作的正确性, DBMS 的并行控制机制必须提供一定的手段来保证调度是可 串行化的。

从理论上讲, 在某一事务执行时禁止其他事务执行的调度策略一定是可串行化的调度, 这也 是最简单的调度策略, 但这种方法实际上是不可行的, 因为它使用户不能充分共享数据库资 源。

目前 DBMS 普遍采用封锁方法(悲观方法, DM 采用的就是这种方法, SQL Server 也是采 用的这种方法) 来保证调度的正确性; 即保证并行操作调度的可串行性。 除此之外还有其他 一些方法,如时标方法、乐观方法等。

• 悲观并发控制

锁定系统阻挠用户以影响其它用户的方式修改数据。如果用户执行的操作导致应用了某个 锁, 则直到这个锁的所有者释放该锁, 其它用户才干执行与该锁冲突的操作。 该方法主要用 在数据争夺激烈的环境中, 以及浮现并发冲突时用锁保护数据的成本比回滚事务的成本低的 环境中,因此称该方法为悲观并发控制。

• 乐观并发控制

在乐观并发控制中, 用户读数据时不锁定数据。在执行更新时,系统进行检查,查看另一个 用户读过数据后是否更改了数据。 如果另一个用户更新了数据, 将产生一个错误。 普通情况 下, 接收错误信息的用户将回滚事务并重新开始。 该方法主要用在数据争夺少的环境内, 以 及偶尔回滚事务的成本超过读数据时锁定数据的成本的环境内,因此称该方法为乐观并发控 制。

时标并发控制

时标和封锁技术之间的基本区别是封锁是使一组事务的并发执行 (即交叉执行) 同步, 使用 它等价于这些事务的某一串行操作; 时标法也是使用一组事务的交叉执行同步, 但是使它等 价于这些事务的一个特定的串行执行,即由时标的时序所确定的一个执行。如果发生冲突, 是通过撤销并重新启动一个事务解决的。事务重新启动,则赋予新的时标。

(三) 封锁

封锁是事项并发控制的一个非常重要的技术。所谓封锁就是事务T 在对某个数据对象,例 如,在标、记录等操作之前,先向系统发出请求,对其加锁。加锁后事务T 就对数据库对 象有了一定的控制,在事务 T 释放它的锁之前,其他事务不能更新此数据对象。 1. 封锁类型

DBMS 通常提供了多种数据类型的封锁。一个事务对某个数据对象加锁后究竟拥有什么样 的控制是由封锁类型决定的。基本的封锁类型有两种:排他锁(exclusive lock,简记为 X 锁)和共享锁(share lock 简记为 S 锁)

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

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

排他锁与共享锁的控制方式可以用下图的相容矩阵来表示。

在下图的封锁类型相容矩阵中,最左边一列表示事务T1 已经获得的数据对象上的锁的类型, 其中横线表示没有加锁。 最上面一行表示另一事务 T2 对同一数据对象发出的封锁请求。 T2 的封锁请求能否被满足用 Y 和 N 表示,其中 Y 表示事务 T2 的封锁要求与 T1 已持有的锁相 容,封锁请求可以满足。 N 表示 T2 的封锁请求与 T1 已持有的锁冲突, T2 请求被拒绝。

2. 封锁粒度

X 锁和 S 锁都是加在某一个数据对象上的。封锁的对象可以是逻辑单元,也可以是物理单 元。例如,在关系数据库中,封锁对象可以是属性值、属性值集合、元组、关系、索引项、 整个索引、整个数据库等逻辑单元;也可以是页(数据页或者索引页)、块等物理单元。封锁 对象可以很大, 比如对整个数据库加锁, 也可以很小,比如只对某个属性值加锁。封锁对象 的大小称为封锁的粒度(granularity)。

封锁粒度与系统的并发度和并发控制的开消密切相关。封锁的粒度越大, 系统中能够被封锁 的对象就越小,并发度也就越小,但同时系统开消也越小;相反,封锁的粒度越小,并发度 越高,但系统开消也就越大。

因此,如果在一个系统中同时存在不同大小的封锁单元供不同的事务选择使用是比较理想 的。而选择封锁粒度时必须同时考虑封锁机构和并发度两个因素, 对系统开消与并发度进行 权衡, 以求得最优的效果。 普通说来, 需要处理大量元组的用户事务可以以关系为封锁单元; 需要处理多个关系的大量元组的用户事务可以以数据库为封锁单位;而对于一个处理少量元 组的用户事务,可以以元组为封锁单位以提高并发度。

3. 封锁协议

封锁的目的是为了保证能够正确地调度并发操作。为此,在运用X 锁和 S 锁这两种基本封 锁,对一定粒度的数据对象加锁时,还需要约定一些规则,例如,应何时申请X 锁或者 S 锁、 持锁时间、何时释放等。我们称这些规则为封锁协议(locking protocol)。对封锁方式规定 不同的规则, 就形成为了各种不同的封锁协议, 它们分别在不同的程度上为并发操作的正确调 度提供一定的保证。本节介绍保证数据一致性的三级封锁协议和保证并行调度可串行性的两 段锁协议,下一节将介绍避免死锁的封锁协议。

(5) 保证数据一致性的封锁协议 ――三级封锁协议

对并发操作的不正确调度可能会带来四种数据不一致性: 丢失或者覆盖更新、 脏读、 不可重复 读和幻想读。三级封锁协议分别在不同程度上解决了这一问题。

① 1 级封锁协议

1 级封锁协议的内容是:事务 T 在修改数据 R 之前必须先对其加 X 锁,直到事务结束才释 放。事务结束包括正常结束(commit)和非正常结束(rollback)。

1 级封锁协议可以防止丢失或者覆盖更新,并保证事务T 是可以恢复的。例如,下图使用 1 级封锁协议解决了定飞机票例子的丢失更新问题。

上图中,事务 1 在读 A 进行修改之前先对 A 加 X 锁,当事务 2 再请求对 A 加 X 锁时被拒绝,

只能等事务 1 释放 A 上的锁。事务 1 修改值 A=15 写回磁盘,释放 A 上的 X 锁后,事务 2 获得对 A 的 X 锁,这时他读到的 A 已是事务 1 更新过的值 15,再按此新的 A 值进行运 算,并将结果值 A=14 回到磁盘。这样就避免了丢失事务 1 的更新。

在 1 级封锁协议中,如果仅仅是读数据不对其进行修改,是不需要加锁的,所以它不能保 证可重复读和脏读。

② 2 级封锁协议

2 级封锁协议的内容是: 1 级封锁协议加之事务 T 在读取数据 R 之前必须先对其加 S 锁, 读完后即可释放 S 锁。

2 级封锁协议除防止了丢失或者覆盖更新,还可进一步防止脏读。例如,下图使用2 级封锁协 议解决了脏读的问题。 |

下图中,事务 1 在对 C 进行修改之前,先对 C 加 X 锁,修改其值后写回磁盘。这时事务 2 请求 C 加之 S 锁,因 T1 已在 C 上加了X 锁,事务 2 只能等待事务 1 释放它。之后事务 1 因某种原因被撤销, C 恢复为原值 100,并释放 C 上的 X 锁。事务 2 获得 C 上的 S 锁,读 C=100。这就避免了事务 2 脏读数据。

在 2 级封锁协议中,由于读完数据后即可释放 S 锁,所以它不能保证可重复读。

③ 3 级封锁协议

3 级封锁协议的内容是: 1 级封锁协议加之事务 T 在读取数据之前必须先对其加 S 锁, 直到 事务结束才释放。

3 级封锁协议除防止丢失或者覆盖更新和不脏读数据外,还进一步防止了不可重复读和幻想 读。例如下图,使用 3 级封锁协议解决了不可重复读和幻像读问题。

上图中, 事务 1 在读 A,B 之前, 先对 A,B 加 S 锁, 这样其他事务只能再对 A,B 加 S 锁, 而不能加 X 锁,即其他事务只能读A ,B,而不能修改它们。所以当事务2 为修改 B 而申请

对 B 的 X 锁时被拒绝,使其他无法执行修改操作,只能等待事务1 释放 B 上的锁。接着事 务 1 为验算再读 A,B,这时读出的 B 仍是 100,求和结果仍为 150,即可重复读。

上述三级协议的主要区别在于什么操作需要申请封锁以及何时释放锁 (即持锁时间) 。三级 封锁协议可以总结为下表。

(6) 保证并行调度可串行性的封锁协议――两段封锁协议

可串行性是并行调度正确性的惟一准则, 两段锁(two-phase locking,简称 2PL) 协议是为 保证并行调度可串行性而提供的封锁协议。

两段封锁协议规定:

①在对任何数据进行读、 写操作之前, 事务首先要获得对该数据的封锁, 而且②在释放一个 封锁之后,事务再也不获得任何其他封锁。

所谓“两段”锁的含义是,事务分为两个阶段,第一阶段是获得封锁,也称为扩展阶段,第二 阶段是释放封锁,也称为收缩阶段。

例如,事务 1 的封锁序列是:

Slock A... Slock B… Xlock C… Unlock B… Unlock A… Unlock C;

事务 2 的封锁序列是:

Slock A... Unlock A… Slock B… Xlock C… Unlock C… Unlock B;

则事务 1 遵守两段封锁协议,而事务 2 不遵守两段封锁协议。

可以证明, 若并行执行的所有事务均遵守两段锁协议, 则对这些事务的所有并行调度策略都 是可串行化的。 因此我们得出如下结论: 所有遵守两段锁协议的事务, 其并行的结果一定是 正确的。

需要说明的是, 事务遵守两段锁协议是可串行化调度的充分条件, 而不是必要条件。 即可串 行化的调度中,不一定所有事务都必须符合两段封锁协议。例如,在下图中,(a)和(b) 都是可串行化的调度,但(a)遵守两段锁协议,(b)不遵守两段锁协议。

4. 死锁和活锁

封锁技术可以有效地解决并行操作的一致性问题, 但也带来一些新的问题, 即死锁和活锁的 问题。

(1) 活锁

如果事务 T1 封锁了数据对象 R 后,事务T2 也请求封锁 R,于是 T2 等待。接着T3 也请求 封锁 R 。T1 释放 R 上的锁后,系统首先批准了T3 的请求, T2 只得继续等待。接着 T4 也 请求封锁 R,T3 释放 R 上的锁后,系统又批准了T4 的请求…… ,T2 有可能就这样永远等 待下去。这就是活锁的情形,如下图所示。

避免活锁的简单方法是采用先来先服务的策略。 当多个事务请求封锁同一数据对象时, 封锁 子系统按请求封锁的先后次序对这些事务排队, 该数据对象上的锁一旦释放, 首先批准申请 队列中第一个事务获得锁。

(2) 死锁

如果事务 T1 封锁了数据 A,事务 T2 封锁了数据 B。之后 T1 又申请封锁数据 B,因 T2 已 封锁了 B,于是 T1 等待 T2 释放 B 上的锁。接着T2 又申请封锁 A,因 T1 已封锁了 A,T2 也只能等待 T1 释放 A 上的锁。这样就浮现了T1 在等待 T2,而 T2 又在等待 T1 的局面, T1 和 T2 两个事务永远不能结束,形成死锁。如下图所示。

死锁问题在操作系统和普通并行处理中已做了深入研究, 但数据库系统有其自己的特点, 操 作系统中解决死锁的方法并不一定合适数据库系统。

目前在数据库中解决死锁问题主要有两类方法,一类方法是采取一定措施来预防死锁的发 生,另一类方法是允许发生死锁,采用一定手段定期诊断系统中有无死锁,若有则解除之。

① 死锁的预防

在数据库系统中, 产生死锁的原因是两个或者多个事务都已封锁了一些数据对象, 然后又都请 求对已为其他事务封锁的数据对象加锁, 从而浮现死锁等待。 防止死锁的发生其实就是要破 坏产生死锁的条件。预防死锁通常有两种方法。

◆ 一次封锁法

一次封锁法要求每一个事务必须一次将所有要使用的数据全部加锁, 否则就不能继续执行。 例 如,在上图的例子中,如果事务 T1将数据对象 A 和 B 一次加锁, T1 就可以执行下去,而 T2 等待。 T1 执行完后释放 A,B 上的锁, T2 继续执行。这样就不会发生死锁。

一次封锁法虽然可以有效地防止死锁的发生, 但也存在问题。 第一, 一次就将以后要用到的 全部数据加锁, 势必扩大了封锁的范围, 从而降低了系统的并发度。第二, 数据库中数据是 不断变化的, 原来不要求封锁的数据, 在执行过程中可能会变成封锁对象, 所以很难实现精 确地确定每一个事务所要封锁的数据对象, 只能采取扩大封锁范围, 将事务在执行过程中可能 要封锁的数据对象全部加锁,这就进一步降低了并发度。

◆ 顺序封锁法

顺序封锁法是预先对数据对象规定一个封锁顺序, 所有事务都按这个顺序执行封锁。 在上例 中,我们规定封锁顺是A,B ,T1 和 T2 都按此顺序封锁,即T2 也必须先封锁 A。当 T2 请 求 A 的封锁时,由于T1 已经封锁住 A,T2 就只能等待。 T1 释放 A,B 上的锁后, T2 继续 运行。这样就不会发生死锁。

顺序封锁法同样可以有效地防止死锁, 但也同样存在问题。 第一, 数据库系统中可封锁的数 据对象及其众多, 并且随数据的插入、 删除等操作而不断地变化, 要维护这样极多而且变化 的资源的封锁顺序非常艰难,成本很高。

第二, 事务的封锁请求可以随着事务的执行而动态地决定, 很难事先确定每一个事务要封锁 哪些对象,因此也就很难按规定的顺序取施加封锁。例如,规定数据对象的封锁顺序为A, B ,C ,D ,E。事务 T3 起初要求封锁数据对象 B,C,E,但当它封锁 B ,C 后,才发现还

需要封锁 A ,这样就破坏了封锁顺序。

可见,在操作系统中广为采用的预防死锁的策略并不很适合数据库的特点,因此DBMS 在 解决死锁的问题上更普遍采用的是诊断并解除死锁的方法。 ② 死锁的诊断与解除

数据库系统中诊断死锁的方法与操作系统类似, 即使用一个事务等待图, 它动态地反映所有 事务的等待状况。并发控制子系统周期性地(比如每隔 1 分钟)检测事务等待图,如果发 现图中存在回路, 则表示系统中浮现了死锁。 关于诊断死锁的详细讨论请参阅操作系统的有 关书籍。

DBMS 的并发控制子系统一旦检测到系统中存在死锁,就要设法解除。通常采用的方法是 选择一个处理死锁代价最小的事务, 将其撤销, 释放此事务持有的所有的锁, 使其他事务能 继续运行下去。 二、 DM 的并发控制 (一) 事务隔离级

事务的隔离级描述了给定事务的行为对其它并发执行事务的暴露程度。 SQL-92 共规定了 四种隔离级别,通过选择四个隔离级中的一个,用户能增加对其它未提交事务的暴露程度, 获得更高的并发度。隔离级别是一个事务必须与其它事务进行隔离的程度。 SQL-92 的四种隔离级别如下所示, DM 支持所有这些隔离级别:

(1)脏读(READ UNCOMMITTED):事务隔离的最低级别,事务可能查询到其它事务 未提交的数据, 仅可保证不读取物理损坏的数据)。

(2)读提交(READ COMMITTED): DM 默认级别,保证不读脏数据。

(3)可重复读(REPEATABLE READ):保证不可重复读,但有可能读入幻像数据。 (4)可串行化(SERIALIZABLE):事务隔离的最高级别,事务之间彻底隔离。 DM 允许用户改变未启动的事务的隔离级和读写特性 ,而且设置的选项将向来对那个连接 保持有效, 直到显式更改该选项为止。 设置事务隔离级别虽然使程序员承担了某些完整性问 题所带来的风险, 但可以换取对数据更大的并发访问权。 与以前的隔离级别相比, 每一个隔离 级别都提供了更大的隔离性, 但这是通过在更长的时间内占用更多限制锁换来的。 DM 还提 供设置事务只读属性的语句,使用该语句后该事务只能做查询操作,不能更新数据库。 需要注意的是, 事务的隔离级别并不影响事务查看本身对数据的修改, 也就是说, 事务总可 以查看自己对数据的修改。 事务的隔离级别需要根据实际需要设定, 较低的隔离级别可以增 加并发,但代价是降低数据的正确性。相反, 较高的隔离级别可以确保数据的正确性, 但可 能对并发产生负面影响。应用程序要求的隔离级别确定了 DM 使用的锁定行为。 下表中列出四种隔离级别允许不同类型的现象

注意:丢失或者覆盖更新在所有的标准 SQL 隔离级中都是禁止的。

(二) 并发处理

1. 数据锁定机制

DM 用数据锁定机制来解决并发问题。它可以保证任何时候都可以有多个正在运行的事务, 但是所有事务都在彼此彻底隔离的环境中运行。

DM 的封锁对象为表和元组。封锁的实施有自动和手动两种,即隐式上锁和显式上锁。隐式 封锁动作的封锁根据事务的隔离级有所不同。同时, DM 提供给用户 4 种手动上锁语句, 用以适应用户定义的应用系统。

普通而言, DM 的隐式封锁足以保证数据的一致性,但用户可以根据自己的需要改变对表 的封锁。 DM 提供给用户四种表锁:意向共享锁(IS:INTENSIVE SHARE)、共享锁 (S:SHARE)、意向排它锁(IX:INTENSIVE EXCLUSIVE)和排它锁(X:EXCLUSIVE)。 例如,在读提交隔离级下,系统缺省的表锁是 IS 或者 IX ,在这两种表锁下,在访问元组前 还需对元组进行封锁,为了提高系统的效率,用户可以手动对表进行 X 封锁,这样,就不 需对访问元组封锁。

封锁机制要达到以下目的:

(1)一致性:保证用户正在查看时,改变的数据并未从根本上发生变化。

(2)完整性:保证数据库的基本结构以正确的顺序,准确地反映对它们的所有改变。

一个“ 锁定” 可以认为是当某一进程需要防止其它进程做某事时获得的某种东西,当该进程 再也不关心此事时就 “释放 ”此锁定,通常一个锁定是加在某个 “资源 ”(某些客体,如表 )上 的。

DM 的内部锁定是自动完成的。 当某一进程要查看一个客体但不允许其他人修改它时, 就获 得一个共享方式的锁定。 当某一进程要修改一客体, 并且防止任何其它进程修改它时, 就获 得更新方式的锁定。 当某一进程要修改一客体, 并且防止任何其它进程修改它或者以共享方式 封锁它时,就获得独占方式的锁定。

2. 锁定类型

DM 中的锁有三种,表锁、行锁和键范围锁。

◆ 表锁

表锁用来封锁表对象,在对表进行检索和更新时, DM 会对表对象进行封锁,但是DM 为用 户提供手动的表锁语句, 用户可以根据自己的需要改变对表的封锁类型。 表锁的模式: 意向 共享锁 IS,意向排它锁 IX,共享锁 S,排它锁 X,共四种,其相容矩阵可定义如下表。

◆ 行锁

行锁封锁元组,在存取元组和更新元组前, DM 会对元组上行锁,系统不提供手动的行封 锁语句。行锁有两种模式:共享锁(S)、排它锁(X),其相容矩阵定义如下表。

◆ 键范围锁

键范围锁用在可串行事务上, 主要解决了幻像读并发问题。 键范围锁覆盖单个记录以及记录 之间的范围, 可以防止对事务访问的记录集进行幻像插入或者删除。键范围锁仅用于在可串行 隔离级别上操作的事务。

可串行性要求, 如果任意一个查询在一个事务中后面的某一时刻再次执行, 其所获取的行集 应与该查询在同一事务中以前执行时所获得的行集相同。如果本查询试图提取的行不存在, 则在试图访问该行的事务完成之前,其它事务不能插入该行。如果允许另一个事务插入该行, 则它将以幻像浮现。

如果另一个事务试图插入驻留在锁定数据页上的行, 页级锁定可以防止添加幻像行, 并维护 可串行性。 但是, 如果该行要添加到未被第一个事务锁定的数据页, 应设定锁定机制防止添 加该行。

键范围锁通过覆盖索引行和索引行之间的范围来工作 (而不是锁定整个基础表的行) 。因为 第二个事务在该范围内进行任何行插入、 更新或者删除操作时均需要修改索引, 而键范围锁覆 盖了索引项,所以在第一个事务完成之前会阻塞第二个事务的进行。

键范围锁由系统自行执行,执行的条件是: (1) 事务隔离级为可串行化级; (2) 查询结果 通过某个索引得出。

用户上锁成功后锁将向来有效,直到当前事务结束时,该锁被系统自动解除。

3. 锁定类型比较

4. SQL 语句锁定分析

DM 对各种 DDL 和 GRANT 等非 DML 语句都分解为增、 删、 改。下表为 DM 对各种 DML 语句和查询语句的封锁策略。

表: SQL 语句封锁策略

注: S* 表示瞬时锁,在语句结束后释放; Range 表示键范围锁。 上表只是系统在普通情况下的处理, 当系统检测到有锁升级的可能, 则会升级锁。 普通而言, IS 锁升级为 S 锁, IX 锁升级为 X 锁,同时,再也不进行行封锁。 5. 自定义锁定提高系统效率 DM 也提供了两个函数 SET_TABLE_OPTION([db.][sch.]tablename, option, value) 、 SET_INDEX_OPTION([db.]indexname, option, value) (具体语法参见《 DM_SQL 语言使 用手册》第 8 章)供用户自行定义锁定类型,以增强系统并发度,提高系统效率。这两个 函数是为那些清晰地知道特定类型的锁合用于何种情况的专家级用户提供的。 函数 SET_TABLE_OPTION() 用于禁用指定表上的页级锁、行级锁或者同时禁用二者,这一 设置对该表上的所有索引都生效。函数 SET_INDEX_OPTION() 则用于禁用某一索引上的 页级锁、行级锁或者同时禁用二者。 例如,当用户只需要修改索引中某定长字段时,修改操作不会造成 B 树的分裂与合并,此 时就可以禁用该索引的页级锁。 又如, 当所有的用户都只做插入操作时, 用户之间并不会对 同一元组进行操作,此时就可以禁用行级锁。当用户能保证不对表进行增、删、改,而只是 进行查询时,则可以同时禁用该表上的页级锁和行级锁,此时并发度最高。 6. 死锁处理

解决死锁问题的三种方法: 预防死锁、 检测死锁及避免死锁。 死锁预防要求用户进程事先申 报所需的资源或者按严格的规程申请资源, 而死锁检测原则上应允许死锁发生, 在适当的时机 检查,若发生死锁,则设法排除之。与预防死锁相比,后者过于放手,导致死锁频繁。而避 免死锁则以事务撤销为前提, 当不能获得资源批准时, 立刻进行死锁检测。 它既不象预防死

锁那样过于保守,也不象死锁检测那样过于放开, 由于检测及时, 由归纳法可知, 在已获准 等待的事务中,不可能存在死锁,所以检测算法比较简单。

DM4 系统采用的是避免死锁方法。每当一个事务所申请占有的资源不能被即将获得时,便 进行死锁检测,不存在死锁,则该事务入等待队列。否则, DM4 视为产生运行时错误,将 当前语句回滚。采用这种机制,从用户的角度看, DM4 不存在解锁问题。

7. 加索引和不加索引的封锁区别

加索引和不加索引的情况下, DM 的封锁机制会影响到实际的封锁范围。索引的作用就在于, 可以在查询中减少对无关数据的扫描。 而在普通的隔离级中, 总是要对扫描到的数据进行封 锁。所以,利用索引可以减少封锁的数量,冲突的可能性也会大大减少。

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- sarr.cn 版权所有

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务