2009年1月4日星期日

Oracle 的锁基础原理

Oracle有以下类别的锁,本文主要只讨论DML的锁

•DML locks (data locks)

•DDL locks (dictionary locks)

•Oracle Internal Locks/Latches

•Oracle Distributed Locks

•Oracle Parallell Cache Management Locks

DML的锁是针对并发数据访问的,因此分行级别TX和表级别TM

两种经典锁

共享锁S表示其他事务可以读取这个资源但是任何事务都不可以更改这个资源,任何事物都不可以再加X锁。

排他锁X表示其他事务可以读取资源,但只有当前事务可以更改这个资源,其他任何事物都不可以再加S或者X锁。

行级锁

也叫事务锁,简称TX锁。两种经典锁,行级别上面只支持X锁(排它锁),Oracle没有行级别S锁(共享锁)。所有DML操作一般自动生成行级锁,行级别锁理论上比表级别锁效率高,因为他的锁定范围更小更精确。

Oracle当中一个记录被insert/update/delete/select for update之后,当前事务T1自动获得这行的X排他锁,另外一个事务T2如果要更改这条记录,另外一个事务T2会被阻塞,直到T1提交或者回滚。

比如

步骤 T1 T2 备注
1 update row1
2 update row1 T2被阻塞
3 commit T1提交,T2可以继续
4 commit

如果在第一步之后,你执行select * from v$lock where type in ('TX','TM'),你就会看到有一个行级别锁TX

image

其中LMODE=3和REQUEST=0,其中LMODE是已经获得的锁模式,取值从0到6, 对于行级别锁其实唯一的值是6,其他值都是对表级别锁的。REQUEST表示要求的锁,如果一个事务所要求的锁需要等待另一个事务释放,那么REQUEST可以看到这个事务需要请求什么类型的锁。

0 NO LOCK
1 NULL
2 RS (Row Share)
3 RX (Row Exclusive)
4 S (Share)
5 SRX (Share + Row Exclusive)
6 X (Exclusive)

这里这个行级别锁TX已经获得了在行row1上的排他锁。

如果在第二步执行之后,T2会被阻塞,你打开一个新的连接再一次执行select * from v$lock where type in ('TX','TM'),你就会看到多出来一个行级别锁TX

image

这个新多出来的行级别锁在row1上获得锁是0(无),要求锁是6(X),同时,刚才那个行级别锁的block标志位变成了1,表示有别的事务等待我释放这个锁。

然后如果你提交T1,T2获得锁,可以继续下去,相应的只剩下了T2的row1上的锁,而且LMODE从0变成了6, REQUEST从6变成了0

image

另外,这时候T1会自动在表级别也加一个锁,目的是防止事务过程中发生DDL操作。其中SID是session ID,可以通过V$session查看,ID1和ID2是rollback segment和transaction table entry.

表级锁

简称TM锁,可分为以下5种

RS: row share,意向锁,表示表内部分行有S锁了,部分行不许更改了

RX: row exclusive ,意向锁,表示表内部分行有变更,有X锁了

S: share ,整个表有S锁,这个表不可以更改

SRX: share + row exclusive,只有一个事务可以获得SRX锁,其他事务可以查询但是不可以更改

X: exclusive, 只有一个事务可以获得X表锁, 其他事务只能查询

RS,RX比较特殊,他们是DML操作产生的常见表级锁,他们都只是意向锁,真正的加锁粒度还是在行级,相当于某些行被锁之后,用这两个意向锁锁一下所属的表,数据库会比较容易判断行级别的锁情况。

从刚才的例子中可以看到,TX总是伴随着一个LMODE=3的TM锁,即RX锁,只要表中有行有X锁,表就会有RX锁。RX表示事务已经更改了某些行,比如insert/update/delete,获得了某些行X锁。RX不会阻塞RX锁,除非行锁上有阻塞。刚才的例子,如果两个事务更改的是两个记录,那么就不会互相阻塞。

如果执行了lock table test in row share mode你会看到LMODE=2(Row Share)的一个表级别锁。RS级别的锁只阻止X级别表锁,它不阻止RS, S等。

image

详细的锁之间的关系如下(相信大多数人就算是理解了也要要想半天的)image

1 条评论:

Unknown 说...

select for update应该是获得RS锁,但是我测试下来,因为select for udpate会给行级别加X锁,所以表锁会自动升级到RX,而不是RS。有人知道为什么这个表格中select for update是RS么?