首页 > 代码库 > Oracle锁2:DML操作和锁

Oracle锁2:DML操作和锁

Oracle为DML操作自动获取行锁和表锁,操作的类型决定了锁的行为,下面对DML操作锁的情况作了一个汇总:

SQL StatementRow LocksTable Lock ModeRSRXSSRXX
SELECT ... FROM table...——noneYYYYY
INSERT INTO table ...YesSXYYNNN
UPDATE table ...YesSXY(注)Y(注)NNN
MERGE INTO table ...YesSXYYNNN
DELETE FROM table ...YesSXY(注)Y(注)NNN
SELECT ... FROM tableFORUPDATEOF ...YesSXY(注)Y(注)NNN
LOCK TABLE tableIN ...——      
ROW SHARE MODE SSYYYYN
ROW EXCLUSIVE MODE SXYYNNN
SHARE MODE SYNYNN
SHARE ROW EXCLUSIVE MODE SSXYNNNN
EXCLUSIVE MODE XNNNNN

注:如果另一个事务和当前事务出现行冲突,则需要等待

下面阐述当行被查询和修改时会涉及到的锁。

当行被查询时的锁

一个查询可以直接通过SELECT查询数据,或者其它语句间接的查询数据,如:INSERT、MERGE、UPDATE和DELETE,其中只有INSERT操作不是必定会涉及到查询的。因为查询仅读数据,因此他们被其它DML语句干涉的可能性是最小的。
如果查询没有FOR UPDATE子句,则查询时:
1)查询不要求数据锁,因此,其它事务能查询和更新正在被查询的数据;
2)查询不必等待任何数据锁被释放,因此,查询总是能执行。一个例外是查询必须等待分布式事务的一些特定的数据锁。

当行被修改时的锁

一些数据库使用一个内存中的列表来维护锁,但Oracle数据库存储锁信息在数据块中,信息包含了被锁的行,每个行锁仅影响一行数据。
Oracle数据库为行锁的获取使用了一个队列机制,如果一个事务请求一个行锁,并且行未被锁,那么事务获取行的数据块的一个锁,事务自身会在数据块头的interested transaction list(ITL)区域放一个条目,被事务修改的每一行都指向ITL中存储的事务ID的一个拷贝,因此,被单个事务修改的在同一块中的100行数据会要求100个行锁,但是所有100行都引用同一个事务ID。
当事务结束时,事务ID保留在数据块头的ITL区域中。如果一个新的事物想修改一行,那么它使用事务ID判断该锁是否是激活的,如果锁是激活的,那么新事务的session会请求在锁被释放时被通知,否则,新事务获取锁。
INSERT、UPDATE、DELETE和SELECT ... FOR UPDATE将满足:
1)使用这些DML操作的事务将在修改的行上请求排它行锁,因此,其它事务不能更新或者删除锁定的行,直到事务commit或者roll back;
2)除了行锁,使用这些DML操作的事务至少需要请求一个子排它表锁(subexclusive table lock,SX)。如果事务已经拥有了一个S、SRX或者X表锁(比SX锁有更强的限制),那么SX锁不被需要;如果事务已经拥有了一个SS锁,那么Oracle数据库自动转换SS锁到SX锁;
3)除非涉及的行被修改,事务不会对任何子查询或者隐含的子查询涉及的行加行锁;例如下面的update操作,使用那个了一个子查询(括号中的部分)和隐含子查询(WHERE a > 5):
UPDATE t SET x = ( SELECT y FROM t2 WHERE t2.z = t.z ) WHERE a > 5;
事务将不会对子查询(SELECT y FROM t2 WHERE t2.z = t.z)涉及的行加锁。
4)在同一个事务中,一个查询能看到先前的DML语句修改的行,但不能看到其它事务未提交的改变。

Oracle锁2:DML操作和锁