事务

事务的特性:

  • Atomicity(原子性):一个事务要么完全执行,要么就不执行。
  • Consistency(一致性):再没有其他事务并发执行的情况下保持数据库的一致性。
  • Isolation(隔离性):一个事务的执行过程中无法感受其他事务的执行。
  • Durability(持久性):一个事务完成后,其结果应写回磁盘。

可串行化:

在并发执行中,通过保证所有执行的任何调度的效果都与没有并发执行的调度效果一样,我们可以确保数据库的一致性。也就是说没调度应该在某种意义上等价于一个串行调度。这种调度称为可串行化。

显然,串行调度是可串行化的,但是如果许多事务的步骤交错执行,则很难确定一个调度是否是可串行化的。

由于事务就是程序,因此要确定一个事务有哪些操作,多个事务的操作如何相互作用是有困难的。

优先图:

为了确定一个调度是否可串行化,我们可以使用优先图。该图由两个部分组成G=(V,E),其中V是顶点集,E是边集,顶点集由所有参与调度的事务组成,边集由满足下列条件之一的Ti→Tj组成:

在Tj执行read(Q)之前,Ti执行write(Q)。

在Tj执行write(Q)之前,Ti执行read(Q)。

在Tj执行write(Q)之前,Ti执行write(Q)。

如果优先图中没有环,则调度是可串行化的;否则无法可串行化。

并发控制:

  • 基于锁的协议

给数据项加锁的类型有多种,这里只讨论两种:

共享锁:如果事务Ti获得了数据项Q上的共享锁,则Ti可读但不能写Q。

排他锁:如果事务Ti获得了数据项Q上的排他锁,则Ti既可读又可写Q。

要求每个事务根据自己将对数据项Q进行的操作类型申请适当的锁。该事务将请求发送给并发控制管理器。事务只有在并发控制管理器授予所需锁后才能继续操作。

下图是锁相容性矩阵(其中S表示共享锁,X表示排他锁):

如果事务Ti将要访问的数据项被加上了一个不相容类型的锁,则所有在所有其他事务持有不相容类型锁被释放前,并发控制管理器不会授予锁。因此Ti只好等待,直到所有其他事务持有的不相容锁被释放。

需要注意的是,锁本身并不能保证冲突可串行性,它只是提供了一种手段,只能通过不同的协议(加锁、释放锁的时机)来保证冲突可串行性。

两段封锁协议:读写数据之前要获得锁。每个事务中所有加锁请求都要先于任何一个解锁请求。

两阶段:加锁段,不能有任何解锁操作;解锁段,不能有任何加锁操作。

封锁粒度:指封锁数据项的大小。

粒度单位越大,并发度越小,封锁开销越小;粒度单位越小,并发度越大,封锁开销越大。

  • 基于时间戳的并发控制

每个事务启动时,系统将当前时间作为时间戳赋给这个事务。然后根据时间戳来判断是否存在不可串行化的冲突,如果没有冲突,则予以执行;否则撤销事务,并重启该事务,当然事务也会获得一个更大的时间戳。下图是一个简单的调度规则:其中WT(x),或者RT(x)表示对数据项x最后一次进行写或者读操作的时间

 

但是这样的调度规则任然会存在脏读。

下图是一个改进后的调度规则:其中C(x)表示数据项x的提交位,该位为真,当且仅当最近写x的事务已经提交。

对于调度器:

当收到提交T的请求时:它需要找到T所写的所有数据项x,并指C(x)=true。如果存在等待x被提交的事务,那么这些事务能够被执行。

当收到终止T的请求时:回滚事务T,并且等待T缩写的数据项x的事务需要重新尝试读或写,并检验是否合法。

  • 基于有效性确认的并发控制

调度器:事务在启动时刻被赋予唯一的时间戳,以示其启动顺序。调度器还需要为每个事务维护一个读写数据集合,RS(T)表示事务T读数据的集合;WS(T)表示写数据的集合。

事务分三个阶段进行:读阶段,事务从数据库中读取读集合中的所有元素,事务还在其局部地址空间计算它将要写的所有值;有效性确认阶段,调度器根据相应的规则进行有效性确认;写阶段,事务往数据库中写入其写集合中元素的值。

每个成功确认的事务是在其有效性确认的瞬间执行的。

此外,调度器还要维护三个集合:

有效性确认规则:

 

posted @ 2019-07-29 15:44  2hYan9  阅读(187)  评论(0编辑  收藏  举报