4.4 并发控制
基于锁的协议
基于时间戳的协议
基于验证的协议
多种粒度
多版本方案
死锁处理
插入与删除操作
ORACLE并发控制基于锁的协议
锁是用来控制对数据项的并发存取的机制
数据项可有两种锁方式,
1,排它 (X)方式,数据项可被读写,X-锁用 lock-X指令请求,
2,共享 (S)方式,数据项只能被读,S-锁用 lock-S指令请求,
向并发控制管理器请求锁,仅当锁请求被批准后事务才能继续,
两阶段锁协议
事务锁管理分数据项的加锁和解锁;
加锁阶段,在对任何数据进行读写之前,事务首先要获得对该数据的加锁,在此阶段不能释放锁;
解锁阶段:在开始释放锁后,不能再申请加锁 。
满足两段锁协议的合理调度(遵循给定锁协议的一组事务的调度)都是冲突可串行的。
两阶段锁不能避免死锁
两阶段锁不能避免级联回滚,用称为 严格 (strict)两阶段锁 的改进协议可避免,事务必须保持它的所有排他锁直至提交 /失败,
严密 (rigorous)两阶段锁 更加严格,所有锁都必须保持到事务提交 /失败,在这种协议中事务可按它们提交的次序串行化,
锁转换
带有锁转换的两阶段锁,
– 第一阶段,
– 可获得 lock-S
– 可获得 lock-X
– 可转换 lock-S 到 lock-X (升级 )
– 第二阶段,
– 可释放 lock-S
– 可释放 lock-X
– 可转换 lock-X 到 lock-S (降级 )
本协议确保可串行化,但仍依靠程序员插入各种封锁指令,
多种并发控制粒度
允许数据项具有不同大小,从而定义一个数据粒度层次,
小粒度嵌入在大粒度中
可图示为一棵树 C
当一事务对树中节点显式加锁,它也对该节点的所有后裔隐含地加了同样的锁,
锁粒度 (封锁发生的树层次 ):
– 系粒度 (树中较低层 ),高并发度,高锁开销
– 粗粒度 (树中较高层 ),低锁开销,低并发度粒度层次例例中最高层是整个数据库,
低层依次是 area,file 和 record.
意向锁
除了 S 和 X 锁方式,还有另外三种多粒度的锁方式,
– 意向共享 (IS),表示在树的低层有显式加共享锁,
– 意向排他 (IX):表示在树的低层有显式加排他或共享锁
– 共享及意向排他 (SIX),以该节点为根的子树被显式加共享锁,并且在子树的低层显式加排他锁,
意向锁允许高层节点按 S或 X方式加锁而不需检查所有后裔节点,
意向锁方式的兼容性矩阵
对所有锁方式的兼容性矩阵如下,
IS IX S S IX X
IS
IX
S
S IX
X






事务 Ti 可以根据下列规则来锁一个节点 Q:
1,必须遵守锁兼容性矩阵,
2,树的根必须首先加锁,并且可以任何方式加锁,
3,仅当节点 Q 的父节点当前被 Ti 以 IX或 IS方式加锁时,Q 才可被 Ti 以 S或 IS方式加锁,
4,仅当节点 Q 的父节点当前被 Ti 以 IX或 SIX方式加锁时,Q 才可以被 Ti 以 X,SIX,或 IX方式加锁,
5,仅当 Ti 先前没有对任何节点开锁时才可以对一个节点加锁
(即,Ti 是两阶段的 ).
6,仅当 Q 的子女没有正被 Ti 加锁时,Ti 才可以对节点 Q 开锁,
注意锁是按从根到叶次序获得的,但是按从叶到根次序释放的,
死锁处理
考虑下列两个事务,
T1,write (X) T2,write(Y)
write(Y) write(X)
有死锁的调度
T1 T2
lock-X on X
write (X)
lock-X on Y
write (X)
wait for lock-X on X
wait for lock-X on Y
死锁预防 协议确保系统永远不会进入死锁状态,一些预防策略如下,
– 要求每个事务在开始执行为其所有数据项加锁 (预声明 ).
– 施加所有数据项上的偏序,并要求一个事务只能按偏序指定的次序锁数据项 (基于图的协议 ).
更多死锁预防策略
下列方案仅为死锁预防目的使用事务时间戳,
等待 -死亡 方案 —非抢占式
– 老事务可能等待年轻事务释放数据项,年轻事务永远不会等待老事务,而是回滚,
– 一个事务可能在获得所需数据项之前死亡若干次
伤害 -等待 方案 —抢占式
– 老事务伤害 (强制回滚 )年轻事务而不是等待它,年轻事务可能等待老事务,
– 可能比等待 -死亡方案有较少的回滚,
wait-die scheme
If TS(Ti) < TS(Tj) then Ti Waits
Else
RollBack Ti
Restart Ti with the same TS(Ti)
Endif
wound-wait scheme
If TS(Ti) > TS(Tj) then Ti Waits
Else
RollBack Tj
Restart Tj with the same TS(Tj)
Endif
在 wait-die 和 wound-wait 方案中,回滚的事务重启动时带有原来的时间戳,老事务因此具有对新事务的优先级,
故避免了饿死,
基于超时的方案,
– 事务对一个锁只等待一个指定的时间量,此后,等待超时,事务回滚,
– 因此死锁是不可能的
– 实现简单 ; 但可能有饿死,另外还难以确定合适的超时间隔,
死锁检测
死锁可用等待图描述,即一个二元组 G = (V,E),
– V 是顶点集合 (即系统中的所有事务 )
– E 是边的集合 ; 其中每个元素是一有序对 Ti?Tj,
若 Ti? Tj 属于 E,则存在从 Ti 到 Tj 的有向边,意味着 Ti
等待 Tj 释放数据项,
当 Ti 请求一个正被 Tj 持有的数据项时,边 Ti Tj 被插入到等待图中,仅当 Tj 不再持有 Ti 所需的数据项时,这条边才被删除,
系统处于死锁状态当且仅当等待图有圈,必须周期性地调用死锁检测算法来查找圈,
没有圈的等待图 有圈的等待图死锁恢复
当检测到死锁时,
– 某些事务必须回滚 (作为牺牲品 ) 来打破死锁,选择导致最小代价的事务作为牺牲品,
– 回滚 – 决定事务回滚多远
完全回滚,夭折事务并重启动,
更有效的是只做为打破死锁所必须的回滚,
– 若同一事务总是被选为牺牲品则发生了饿死,在代价因子中包括回滚次数以避免饿死插入与删除操作
如果使用两阶段锁,
– 仅当删除元组的事务对删除元组具有排他锁时,
delete 操作才可以被执行,
– 向数据库插入一条新元组的事务对该元组获得 X锁
插入和删除可能导致 幻影现象,
– 扫描关系的事务 (例如查找所有 Perryridge的账户 ) 和向关系中插入元组的事务 (例如在 Perryridge插入一条新元组 )尽管不存取任何共同的元组也可能冲突,
– 如果只使用元组锁,可导致非串行化调度,扫描事务可能看不到新账户,但可能在插入事务之前串行化,
插入与删除操作 (续 )
扫描关系的事务正在读指明,关系中包含什么元组,的信息,而插入元组的事务则更新这同一信息,
– 该信息应该封锁,
一种解决方法,
– 将关系与一个数据项相关联,该数据项表示,关系中包含什么元组,的信息,
– 扫描关系的事务获得该数据项上的共享锁,
– 插入或删除元组的事务获得该数据项上的排他锁,(注,
该数据项上的锁与各个元组上的锁不冲突,)
上述协议对插入 /删除操作提供了很低的并发性,
索引封锁协议提供了较高的并发性同时防止了幻影现象,
此协议要求对某些索引桶加锁,
索引封锁协议
每个关系必须具有至少一个索引,对关系的存取必须只能通过关系上的一个索引来进行,
执行查找的事务 Ti 必须以共享方式锁住它存取的所有索引桶,
事务 Ti 在更新所有 r 上索引之前不能向关系 r 中插入元组 ti,
Ti 必须对每个索引执行查找以找到所有可能包含指向元组 ti 的指针的索引桶,如果已经存在的话,并且获得这些索引桶上的 X锁,Ti 还必须获得它所更新的所有索引桶上的 X锁,
两阶段封锁协议的规则必须遵守,
ORACLE并发控制
ORACLE总是以事务为单位控制和管理着并发操作所使用的公共资源的,并发操作之间通过使用数据和数据字典锁来维持公共数据资源的完整性和一致性,当一个事务被提交或滚回时,这些资源才被释放。
ORACLE明确支持 Read committed和 Serializable 隔离级别。还支持 Read Only隔离级。
READ COMMITTED:在语句级强制串行化。事务中的每条语句所见的都是在语句开始执行前完成了提交的数据。
同一个事务的同一条语句执行之间,数据可能被其他事务改变,从而出现不可重复读和幻读的情况。
SERIALIZABLE在事务级强制串行化。因而事务中的每条语句所见的都是在事务开始前完成提交的数据。
READ ONLY只读事务仅能看到在事务开始前完成提交的数据。
ORACLE的锁有如下特性:
读者不妨碍写者、
写者不妨碍读者、
读一致性由滚回段支持、
支持表级锁和行级锁、
支持自动加锁和手工加锁、
手工加锁时可加共享锁和排它锁。
ORACLE提供了各种类型的封锁机制保证并发操作时数据的一致,对数据库对象的封锁由系统自动完成。数据库应用设计者可以干预自动封锁过程以提高整体效率,
ORACLE主要封锁类型有,
– 根据保护对象的不同,Oracle数据库锁可以分为以下几大类:
– (1) DML lock( data locks,数据锁):用于保护数据的完整性;
– (2) DDL lock( dictionary locks,字典锁):用于保护数据库对象的结构(例如表、视图、索引的结构定义);
– (3) Internal locks 和 latches(内部锁与闩):保护内部数据库结构;
– (4) Distributed locks(分布式锁):用于 OPS(并行服务器)中;
– (5) PCM locks(并行高速缓存管理锁):用于 OPS(并行服务器)中。
在 Oracle中最主要的锁是 DML(也可称为 data locks,数据锁)锁。
数据锁有两种级别的封锁方式,
– 表封锁,封锁表中的所有行,数据并行度低,
– 行封锁,行级封锁在对应表上加字典锁,
ORACLE表上的数据锁类型有,
共享锁( S锁)
排它锁( X锁)
行级共享锁( RS锁)
行级排它锁( RX锁)
共享行级排它锁( SRX锁)
其中 RS锁,RX锁,SRX锁实际上就是 IS锁,IX锁、
SIX锁。
ORACLE中的 SELECT不用任何数据锁阻塞其他操作,
也称无阻塞查询。 INSERT,UPDATE,DELETE引发数据封锁,事务所申请的全部数据锁在事务提交或回退时一起释放,表上的数据锁也可以通过显式语句完成,
表上的数据锁在事务执行过程中可能发生变化,如事务为执行带 UPDATE子句的 SELECT语句,需在选中行上建立行共享锁,如果稍后事务决定修改其中的某些行,
则这些行上的行共享锁将自动转换为行专有锁。
数据锁的相容矩阵
T1 T2 S X RS RX SRX -
S Y N Y N N Y Y=Yes,表示相容的请求
X N N N N N Y
RS Y N Y Y Y Y N=No,表示不相容的请求
RX N N Y Y N Y
SRX N N Y N N Y
- Y Y Y Y Y Y
SQL语句 封锁 允许模式 RS RX S SRX X
Select 无 Y Y Y Y Y
Insert RX Y Y N N N
Delete RX Y Y N N N
Update RX Y Y N N N
Select for update of RS Y Y Y Y N
Lock table in row share mode RS Y Y Y Y N
Lock table in row exclusive
mode
RX Y Y N N N
Lock table in share mode S Y N Y N N
Lock table in share row
exclusive mode
SRX Y N N N N
Lock table in exclusive mode X N N N N N
Oracle 多粒度封锁机制的监控相关锁系统视图:
1 v$lock视图其中在 TYPE字段的取值中,涉及 TM,TX等锁类型;
2 v$locked_object视图
v$locked_object视图列出当前系统中哪些对象正被锁定,
其主要字段说明如下:
1 Oracle通过具有意向锁的多粒度封锁机制进行并发控制,
保证数据的一致性。其 DML锁(数据锁)分为两个层次
(粒度):即表级和行级。通常的 DML操作在表级获得的只是意向锁( RS或 RX),其真正的封锁粒度还是在行级;
2在 Oracle数据库中,单纯地读数据( SELECT)并不加锁,这些都提高了系统的并发程度,Oracle强调的是能够
,读,到数据,并且能够快速的进行数据读取。
3 Oracle利用意向锁及数据行上加锁标志位等设计技巧,
减小了 Oracle维护行级锁的开销,使其在数据库并发控制方面有着一定的优势。
总结:
4 Oracle数据库中不存在锁升级。
5在 Oracle中当一个 session对表进行 insert,update,
delete时候,另外一个 session仍然可以从 Orace回滚段或者还原表空间中读取该表的前映象( before image),
所以 Oracle同一时刻不同的 session有读不一致的现象。
思考题:
1描述两段锁协议。
2意向锁的类型及其之间的相容性。
3什么是等待方案和等待伤害方案。
4 ORACLE的锁类型和封锁机制。