数据库并发控制之活锁和死锁

一、活锁

活锁的情况:如果事务T1封锁了数据R,事务T2又请求封锁R,于是T2等待;T3也请求封锁R,当T1释放了R上的封锁之后系统首先批准了T3的请求,T2仍然等待;然后T4又请求封锁R,当T3释放了R上的封锁之后系统又批准了T4的请求…T2有可能永远等待。如下图所示:
数据库并发控制之活锁和死锁_第1张图片
避免活锁的简单方法是采用先来先服务的策略。当多个事务请求封锁同一数据对象时,封锁子系统按请求封锁的先后次序对事务排队,数据对象上的锁一旦释放就批准申请队列中第一个事务获得所。

二、死锁

死锁的情形:如果事务T1封锁了数据R1,T2封锁了数据R2,然后T1又请求封锁R2,因T2已封锁了R1,T2也只能等待T1释放R1上的锁。这样就出现了T1在等待T2,而T2又在等待T1的局面,T1和T2两个事务永远不能结束,形成死锁。如图所示:
数据库并发控制之活锁和死锁_第2张图片
死锁的解决方法有:

1、死锁的预防

采取一定措施来预防死锁的发生。在数据库中,产生死锁的原因是两个或多个事务都已封锁了一些数据对象,然后又都请求对已被其他事务封锁的数据对象加锁,从而出现死等待。防止死锁的发生其实就是要破坏产生死锁的条件。预防的方法有:

  1. 一次封锁法
    一次封锁法要求每个事务必须将所有要使用的数据全部加锁,否则就不能继续执行。这种方法虽然可以有效地预防死锁的方式,但是一次就将以后要用到的全部数据加锁,势必扩大了封锁的范围,从而降低了系统的并发度,而且,数据库是不断变化的,原来不要求封锁的数据在执行过程中可能会变成封锁对象,所以很难事先精确地确定每个事务所要封锁的数据对象,为此只能扩大封锁范围,将事务在执行过程中可能要鞥说的数据对象全部加锁,这就进一步降低了并发度。
  2. 顺序封锁法
    顺序封锁法是预先对数据对象规定一个封锁顺序,所有事务都按这个顺序实施封锁。例如在B树结构的索引中,可规定封锁的顺序必须是从根节点开始,然后是下一级的子节点,逐级封锁。
    顺序封锁法可以有效地防止死锁,但是数据库系统中封锁的数据对象极多,并且随数据的插入、删除等操作而不断变化,要维护这样的组员的封锁顺序非常困难,成本很高,而且事务的封锁请求可以随着事务的执行而动态地决定,很难实现确定每一个事务要封锁哪些对象,因此也就很难规定的顺序去施加封锁。
2、 死锁的诊断与解除

允许发生死锁,采用一定手段定期诊断系统中有误死锁,若有则解除之。数据库系统中诊断死锁的方法与操作系统类似,一般使用超时法或事物等待图法。

  1. 超时法
    如果一个事务的等等事件超过了规定的时限,就认为发生了死锁。超时法实现简单,但可能误判死锁。如事务因为其他原因而使等等事件超过时限,系统会误认为发生了死锁。并且,时限如果设置得太长,死锁发生后不能及时发现。
  2. 等待图法
    事务等待图是一个有向G=(T,U),T为结点的集合,每个结点表示正运行的事务;U为边的集合,每条边表示事务等待的情况。若T1等待T2,则在T1、T2之间画一条有向边,从T1指向T2。
    事务等待图如下:(a)事务T1等待T2,T2又的搞得T1,产生了死锁;(b)事务T1等待T2,T2等待T3,T3等待T4,T4又等待T1,产生了死锁。
    数据库并发控制之活锁和死锁_第3张图片
    事务等待图动态地反映了所有事务的等待情况。并发控制子系统周期性地(比如每隔数秒)生成事务等待图,并进行检测。如果发现图中存在回路,则表示系统中出现了死锁。

在出现死锁的时候,死锁的情况可以多种多样。数据数据库管理系统的并发控制子系统一旦检测系统中存在死锁,就要设法解除。通常采用的方法是选择一个处理死锁代价最小的事务,将其撤销,释放此事务持有的所有的锁,使其他事务得以继续运行下去。当然,对撤销的事务所执行的数据修改操作必须加以恢复。

你可能感兴趣的:(数据库)