深入理解数据库原理系列(2)---并发控制原理(摘自老杨)

事务之间的相互影响可能导致数据库状态的不一致,即使各个事务能保持状态的正确性,而且也没有任何故障发生。因此,不同事务中各个步骤的执行顺序必须以某种方式进行规范。控制这些步骤的功能由DBMS的调度器部件完成,而保证并发执行的事务能保持一致性的整个过程称为并发控制。调度器的作用如图1所示。

   首先讨论如何保证并发执行的事务能保持数据库状态的正确性。抽象的要求称为可串行性,另外还有一个更强的、重要的条件为冲突可串行性,它是大多数调度器所真正实现的。我们考虑实现调度器的最重要技术:封锁、时间戳和有效性确认。
1.串行调度和可串行化调度
1.1 调度
   调度是一个或多个事务的重要操作按时间排序的一个序列。
   1 考虑两个事务以及它们的动作按照某些顺序执行时的数据库的影响。 T1 T2 的重要动作如表 1 所示。
1 两个事务
T1
T2
READ(A,t)
READ(A,s)
t := t + 100
s := s*2
WRITE(A,t)
WRITE(A,s)
READ(B,t)
READ(B,s)
t := t + 100
s := s*2
WRTIE(B,t)
WRITE(B,s)
 
1.2 串行调度
   如果一个调度的动作首先是一个事务的所有动作,然后是另一个事务的所有动作,以此类推,而没有动作的混合,那么我们说这一调度是串行的。
   2 对表 1 中的事务而言,两个串口调度,一个是 T1 T2 前,而另一个是 T2 T1 之前,初态为 A=B=25
2 T1 T2 前的串行调度
T1
T2
A
B
 
 
25
25
READ(A,t)
 
 
 
t := t + 100
 
 
 
WRITE(A,t)
 
125
 
READ(B,t)
 
 
 
t := t + 100
 
 
 
WRTIE(B,t)
 
 
125
 
READ(A,s)
 
 
 
s := s*2
 
 
 
WRITE(A,s)
250
 
 
READ(B,s)
 
 
 
s := s*2
 
 
 
WRITE(B,s)
 
250
 
3 T2 T1 前的串行调度
T1
T2
A
B
 
 
25
25
 
READ(A,t)
 
 
 
t := t + 100
 
 
 
WRITE(A,t)
50
 
 
READ(B,t)
 
 
 
t := t + 100
 
 
 
WRTIE(B,t)
 
50
READ(A,s)
 
 
 
s := s*2
 
 
 
WRITE(A,s)
 
150
 
READ(B,s)
 
 
 
s := s*2
 
 
 
WRITE(B,s)
 
 
150
 
 
1.3 可串行化调度
   事务的正确性原则告诉我们,每个串行调度都将保持数据库状态的一致性。
   通常,不管数据库初态怎样,一个调度对数据库状态的影响都和某个串行调度相同,我们就说这个调度是可串行化的。
   3 4 是例 1 中事务的一个调度,此调度是可串行化的,但不是串行的。表 5 不是可串行化的。
5 一个非串行的可串行化调度
T1
T2
A
B
 
 
25
25
READ(A,t)
 
 
 
t := t + 100
 
 
 
WRITE(A,t)
 
125
 
 
READ(A,s)
 
 
 
s := s*2
 
 
 
WRITE(A,s)
250
 
READ(B,t)
 
 
 
t := t + 100
 
 
 
WRTIE(B,t)
 
 
125
 
READ(B,s)
 
 
 
s := s*2
 
 
 
WRITE(B,s)
 
250
 
6 一个非可串行化的调度
T1
T2
A
B
 
 
25
25
READ(A,t)
 
 
 
t := t + 100
 
 
 
WRITE(A,t)
 
125
 
 
READ(A,s)
 
 
 
s := s*2
 
 
 
WRITE(A,s)
250
 
 
READ(B,s)
 
 
 
s := s*2
 
 
 
WRITE(B,s)
 
50
READ(B,t)
 
 
 
t := t + 100
 
 
 
WRTIE(B,t)
 
 
150
 
 
1.4 事务语句的影响
   事务细节确实有关系的,正如我们将在下面的例子中看到的那样。
   4 7 T2 并非将 A B 2 ,而是乘 1 。现在,在这一调度的结尾, A B 的值相等。
7 一个仅仅由于事务细节行为而可串行化的调度
T1
T2
A
B
 
 
25
25
READ(A,t)
 
 
 
t := t + 100
 
 
 
WRITE(A,t)
 
125
 
 
READ(A,s)
 
 
 
s := s*1
 
 
 
WRITE(A,s)
125
 
 
READ(B,s)
 
 
 
s := s*1
 
 
 
WRITE(B,s)
 
25
READ(B,t)
 
 
 
t := t + 100
 
 
 
WRTIE(B,t)
 
 
150
   遗憾的是,调度器考虑事务所进行的计算的细节是不现实的。但是,调度器的确能看到来自事务的读写请求,于是能够知道每个事务读哪些数据库元素,以及它可能改变哪些元素。为了简化调度器的工作,通常假定:
   1 )事务 T 所写的任意数据元素 A 被赋予一个值,该值以这样一种方式依赖于数据库状态,即不会发生算术上的巧合。
 
1.5 事务和调度的一个记法
   我们接受事务所进行的精确计算可以是任意的,那么我们不需要考虑像 t := t+100 这样的局部计算步骤。只有事务的读和写需要考虑。因此,我们将用一种新的记法来表示事务和调度,其中动作有 rT(X) wT(X) 分别表示事务 T 读和写数据库元素 X
   5   1 所示的事务可以写为:
        T1:  r1(A); w1(A); r1(B);w1(B);
        T2: r2(A); w2(A); r2(B);w2(B);
   5 T1 T2 的可串行化调度。这一调度写为:
   r1(A); w1(A); r2(A); w2(A); r1(B);w1(B); r2(B);w2(B);
 
 
为使这一记法更精确:
1 )动作是形如 ri(X) wi(X) 的表达式,分别表示事务 Ti 读或写数据元素 X
2 )事务 Ti 是具有下标 i 的动作序列。
3 )事务集合 T 的调度 S 是一个动作序列,其中对 T 中的每个事务 Ti Ti 中的动作在 S 中出现的顺序和其在 Ti 自身定义出现的顺序一样。我们说 S 是组成它的事务动作的一个交错。
 
2.冲突可串行化
   我们现在将提出一个足以保证调度可串行化的条件。它基于冲突这一概念:调度中一对连续的动作,它们满足:如果它们的顺序交换,那么涉及的事务中至少有一个的行为会改变。
 
2.1 冲突
  大多数的动作对按上面的理解并不冲突。
  不同事务的任意两个动作在顺序上可以交换,除非:
1) 它们涉及同一数据库元素;并且
2) 至少有一个是写。
 
   将这一思想进行扩展,我们可以接受任一调度,进行任意非冲突的交换,目标是将该调度转换为一个串行调度。如果我们能做到这一点,那么初始的调度是可穿行化的,因为它对数据库状态的影响在我们做一个非冲突交换时是不变的。
   我们说两个调度是冲突等价的,如果通过一系列相邻的动作的非冲突化交换能将它们中的一个转换为另一个。如果一个调度冲突等价于一个串行调度,那么我们记说该调度是冲突可串行化的。
   6   考虑例 5 中的调度
          r1(A); w1(A); r2(A); w2(A); r1(B);w1(B); r2(B);w2(B);
   通过交换相邻动作将冲突可串行化调度转换为串行调度
          r1(A); w1(A); r1(B);w1(B);r2(A); w2(A); r2(B);w2(B);
 
 
2.2 优先图及冲突可串行化判断
   已知调度 S ,其中涉及事务 T1 T2 ,可那个还有其他事务,我们说 T1 优先于 T2 ,写作 T1<ST2 ,如果有 T1 的动作 A1 T2 的动作 A2 ,满足:
1) S A1 A2 前;
2) A1 A2 都涉及同一数据库元素;并且
3) A1 A2 至少有一个是写动作。
   这正是我们不能交换 A1 A2 顺序的情况。因此,在任何冲突等价于 S 的调度中, A1 将出现在 A2 的前面。所以,如果这些调度中有一个是串行调度,那么该调度必然是 T1 T2 前。
   我可以使用优先图概括这样的先后次序。优先图中的结点是调度 S 中的事务。如果 Ti<STj ,则有一条从结点 i 到结点 j 的弧。
 
  7 下面的调度 S 涉及三个事务 T1 T2 T3
    S r2(A);r1(B);w2(A);r3(A);w1(B);w3(A);r2(B);w2(B)
判断调度 S 是否是冲突可串行化有一条简单的规则:
1 )构造 S 的优先图,并判断其中是否有环。
如果有,那么 S 不是冲突可串行化的。如果该图是无环的,那么 S 是冲突可串行化的。
 
例8    考虑调度:
     S1: r2(A);r1(B);w2(A); r2(B);r3(A);w1(B);w3(A); w2(B)

   该图中显然有环,我们断定 S1 不是冲突可串行化的。
 
 
3.使用锁的可串行性实现
   设想以一种不受约束的方式进行其动作的事务的一个集合。这些动作将形成以个调度,但是这一调度不大可能是可串行化的。
   我们考虑调度器最常用的体系结构,这种结构在数据库元素上维护“锁”,以防止非可串行化的行为。
   在本节中,我们用一个(过于)简单的封锁模式来介绍封锁的概念。这种模式中只有一种锁,它是事务想要在数据库元素上执行任何操作时都必须在该数据库元素上获得的。
 
 
3.1
   在图 4 中我们看到一个使用锁表来协助自己工作的调度器。

    当调度器使用锁时,事务在读写数据库元素以外还必须申请和释放锁。锁的使用必须在两种意义上都是正确的:一种适用于事务的结构,而另外一种适用于调度的结构。
  ·事务的一致性:动作和锁必须按预期的方式发生联系:
1) 事务只有以前已经在数据库元素上申请了锁并且还没有释放锁时才能读或写该数据元素。
2) 如果事务封锁某个数据库元素,它必须为该元素解锁。
  · 调度的合法性:锁必须具有其预期的含义:任何两个事务都不能封锁同一元素,除非其中一个事务已经先释放其锁。
 
   扩展我们先前关于动作的记法,并加入封锁和解锁动作:
 li(X) :事务 Ti 请求数据库元素 X 上的锁。
 ui(X) :事务 Ti 释放它在数据库元素 X 上的锁(解锁)。
 
   因此,事务的一致性条件可以表述为:“只要事务 Ti 有动作 ri(X) wi(X) ,那么前面必然有一个动作 li(X) 且两者之间没有 ui(X) ,并且后面将会有一个 ui(X) ”。
   调度的合法性表述为:“如果调度中现有 li(X) 后有 lj(X) ,那么这些动作之间的某个地方必然有一个动作 ui(X)
 
 
 
 
 
  考虑例 1 中介绍的事务 T1 T2
  T1:  l1(A);r1(A); A := A+100;w1(A); u1(A);l1(B);r1(B);B:=B+100;w1(B);u1(B);
   T2: l2(A);r2(A); A := A*2;w2(A); u2(A);l2(B);r2(B);B:=B*2;w2(B);u2(B);
 
8 一致事务的一个合法调度;但不幸的是,它不是可串行化的
T1
T2
A
B
 
 
25
25
l1(A);r1(A);
 
 
 
A := A+100 ;
 
 
 
w1(A); u1(A);
 
125
 
 
l2(A);r2(A);
 
 
 
A := A*2 ;
 
 
 
w2(A); u2(A);
250
 
 
l2(B);r2(B);
 
 
 
B:=B*2 ;
 
 
 
w2(B);u2(B);
 
50
l1(B);r1(B);
 
 
 
B:=B+100 ;
 
 
 
w1(B);u1(B);
 
 
150
 
 
3.2 封锁调度器
   基于封锁的调度器的任务是当且仅当请求将产生合法调度时同意请求。为了帮助进行决策,调度器有一个锁表,对于每一个数据库元素,如果其上有锁,那么锁表明当前持有该锁的事务。我们将在 5.2 节更详细地讨论锁表的结构。
 
  10 对来自例 9 T1 T2 稍作修改,其中 T1 T2 都在释放 A 上的锁之前封锁 B
   T1:  l1(A);r1(A); A := A+100;w1(A); l1(B); u1(A);r1(B);B:=B+100;w1(B);u1(B);
   T2: l2(A);r2(A); A := A*2;w2(A); l2(B); u2(A);r2(B);B:=B*2;w2(B);u2(B);
 
T1
T2
A
B
 
 
25
25
l1(A);r1(A);
 
 
 
A := A+100 ;
 
 
 
w1(A); l1(B); u1(A);
 
125
 
 
l2(A);r2(A);
 
 
 
A := A*2 ;
 
 
 
w2(A);
250
 
 
l2(B);
 
 
r1(B);B:=B+100;
 
 
 
w1(B);u1(B);
 
 
125
 
l2(B); u2(A);r2(B);
 
 
 
B:=B*2 ;
 
 
 
w2(B);u2(B);
 
250
 
 
3.3 两阶段封锁
    在一个另人吃惊的条件下,我们可以保证一致事务的合法调度是冲突可串行化的。这一条件称为两阶段封锁或 2PL ,在商用封锁系统中被广泛采用。 2PL 条件是:
   · 在每个事务中,所有封锁请求先于所有解锁请求。
因此 2PL 中所指的“两阶段”是获得锁的第一阶段和释放锁的第二阶段。服从 2PL 条件的事务被称为两阶段封锁事务或 2PL 事务。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值