数据库 __ 基于锁的协议的并发控制
作者:互联网
确保隔离性的方法之一是要求对数据项以互斥的方式进行访问;换句话说,当一个事务访问某个数据项时, 其他任何事务都不能修改该数据项。 实现该需求最常用的方法是只允许事务访问当前该事务持有锁( lock ) 的数据项。
锁
锁就是指:只有获得相应的锁后,才能执行相应的操作。
一个事务只要还在访问数据项,它就必须拥有该数据项上的锁。
我们将锁分为两类:
- 共享锁( 记为S ):当事务获得了排他锁,则可以在该数据项进行读操作。
许多事务可以同时持有一个数据项上的共享锁。 - 排他锁( 记为X ):当事务获得了排他锁,则在该数据项既可读又可写。
只有当其他事务在一个数据项上不持有任何锁( 无论共享锁或排他锁)时,一个事务才允许待有该数据项上的排他锁。
关于锁的几个基本操作:
-
每个事务都要根据自已将对数据项Q进行的操作类型申请适当的锁。
具体来说:一个事务通过执行lock-S ( Q ) 指令来申请数据项Q 上的共享锁。类似地,一个事务通过执行lock-X (Q) 指令来申请排他锁。 -
该事务将请求发送给并发控制管理器。事务只有在并发控制管理器授予所需锁后,才能继续其操作。
锁的授予必然是在事务申请锁操作与事务的下一动作的间隔内。在此期间内授权加锁即可,准确时间并不重要。 -
因此如果该数据项已被另一事务加上了不相容类型的锁,则在所有其他事务持有的不相容类型锁被释放之前, 并发控制管理器不会授予锁,事务只好等待,直到所有其他事务持有的不相容类型锁被释放。
尽管数据项Q 上存在B 类型锁,如果事务T,可以立即获得数据项Q 上的锁,则我们就说A 类型锁与B 类型锁是相容的(compatible) 。
这样的一个函数可以通过矩阵方便地表示出来。
当且仅当类型A 与类型B 是相容的,该矩阵的一个元素comp (A, B ) 具有true 值。
容易得到只有共享型与共享型是相容的,其余都不相容。
两阶段封锁协议
封锁协议: 规定事务何时对数据项们进行加锁、解锁的一组规则。封锁协议限制了可能的调度数目。
常用的保证可串行性的一个协议是两阶段封锁协议。
两段锁协议::要求每个事务分两个阶段提出加锁和解锁申请。
- 增长阶段:事务可以获得锁,但不能释放锁。
- 缩减阶段:事务可以释放锁,但不能获得新锁。
一旦该事务释放了锁,就不能再发出加锁请求。
锁转换:将一种类型的锁改为另一种类型。
- 升级: 表示从共享到排他的转换,
- 降级: 表示从排他到共享的转换。
锁转换不能随意进行,锁升级只能发生在增长阶段,而锁降级只能发生在缩减阶段。
封锁协议作用:
-
我们可以证明两阶段封锁协议保证冲突可串行化。
事务的封锁点: 在调度中事务获得其最后加锁的位置(增长阶段结束点)。
多个事务可以根据它们的封锁点进行排序,这个顺序就是事务的一个可串行化顺序。 -
遵循两阶段封锁也可能会发生死锁。
活锁和死锁
活锁
活锁的情形:
事务T1封锁了数据R
事务T2又请求封锁R,于是T2等待。
T3也请求封锁R,当T1释放了R上的封锁之后系统首先批准了T3的请求,T2仍然等待。
T4又请求封锁R,当T3释放了R上的封锁之后系统又批准了T4的请求……
T2有可能永远等待
**产生原因: ** 有人插队。
避免活锁:
采用先来先服务的策略
或者在等待的权重上加上等待时间
死锁
活锁的情形:
事务T1封锁了数据R1
T2封锁了数据R2
T1又请求封锁R2,因T2已封锁了R2,于是T1等待T2释放R2上的锁
接着T2又申请封锁R1,因T1已封锁了R1,T2也只能等待T1释放R1上的锁
这样T1在等待T2,而T2又在等待T1,T1和T2两个事务永远不能结束,形成死锁
产生死锁的原因
两个或多个事务都已封锁了一些数据对象,然后又都请求对已为其他事务封锁的数据对象加锁,从而出现死等待。
解决死锁的方法
处理死锁问题有两种主要的方法。
- 预防死锁:保证系统永不进入死锁状态。
- 死锁恢复:我们允许系统进人死锁状态,然后试着用死锁检测与死锁恢复机制进行恢复。
两种方法均有可能引起事务回滚。
如果系统进入死锁状态的概率相对较高, 则通常使用死锁预防机制;否则,使用检测与恢复机
制会更有效。
标签:__,数据项,事务,封锁,数据库,T2,T1,并发,死锁 来源: https://www.cnblogs.com/kingwz/p/16368399.html