本文结合示例简要的介绍了一下Oracle中锁的机制。
为了解决多用户环境下并发操作相同的资源而造成的错误修改数据的问题。单用户环境下不需要考虑锁,因为所有操作都是串行的。下面的文章简要的介绍了一下
锁的分类异常复杂,enqueue、latch、mutex等,都是为了解决并发存在的,自己也有些混乱,所以也不过多解释了。下面列举一些对于lock的要点内容。
l 排他锁:
不允许相关的资源被共享。一个资源在一个时间点内只有一个事务能够获取该资源的排他锁,只有持有该锁的事务能够修改相关的资源,
其他想要获取锁的事务只能等待该事务因为commit或者rollback而释放排他锁。
l 共享锁:
允许相关的资源被共享。也就是说允许多个事务同时持有某个资源的共享锁。
对于一个dml操作,会对表以及行加锁,也就是v$lock中的TM锁和TX锁。
l 行级锁基本原理:
行级锁的信息是置于数据块中的,如果要修改某一条记录的值,其实就是在访问相应的block,并且分配一个ITL,然后通过rowid访问
rowpiece header ,如果第二个字节lock byte(lock byte只占用1个字节,最大值为255,这也是为什么maxtrans最大为255)为0,则将其改为分配的ITL slot number。另外一个事务如果也想要修改数据,就会发现lock byte不为0,如果第一个事务还没有结束,则第二个事务进入enqueue等待,也就是transaction enqueue。
关于transaction enqueue有一个很有趣的例子,事务不一定是按照时间的先后顺序进行的。
具体地址在:
http://docs.oracle.com/cd/E11882_01/server.112/e25789/transact.htm#autoId12
l 对于Table lock来说可以分为以下几种类型:
1. Row Share (RS|SS)
2. Row Exclusive Table Lock (RX|SX)
3. Share Table Lock (S)
4. Share Row Exclusive Table Lock (SRX|SSX)
5. Exclusive Table Lock (X)
以下是v$lock.LMODE字段中的数字对应的锁类型
LMODE(Lockmode in which the session holds the lock):
0 -none
1 -null (NULL)
2 -row-S (SS)
3 -row-X (SX)
4 -share (S)
5 -S/Row-X (SSX)
6 -exclusive (X)
为了更好的开展下面的内容,这里列举一下各种TM锁类型的兼容情况。
详细验证情况会在4中给出。
RS|SS
RX|SX
S
SRX|SSX
X
RS|SS
√
√
√
√
×
RX|SX
√
√
×
×
×
S
√
×
√
×
×
SRX|SSX
√
×
×
×
×
X
×
×
×
×
×
顺便引用一下经典内容:
只有被修改时,行才会被锁定。
当一条语句修改了一条记录,只有这条记录上被锁定,在Oracle数据库中不存在锁升级。
当某行被修改时,它将阻塞别人对它的修改。
当一个事务修改一行时,将在这个行上加上行锁(TX),用于阻止其它事务对相同行的修改。
读永远不会阻止写。
读不会阻塞写,但有唯一的一个例外,就是select ...for update。
写永远不会阻塞读。
当一行被修改后,Oracle通过回滚段提供给数据的一致性读
当我们更新一个表的记录的时候,会有两种锁产生,一种是DML锁(TM)也可以称作table lock 还有一种事务锁(TX)也可以称作行锁
在v$lock中可以查看到。
例如下面的例子当中:
_dexter@FAKE>desc tun2_tab
Name Null? Type
------------------------------------------------------------------------- --------------------------------------------
ID NUMBER(38)
_dexter@FAKE>update tun2_tab set id =2 ;
2 rowsupdated.
_dexter@FAKE>select sid , type , lmode , request , block
from v$lock
where sid =(select sid from v$mystat where rownum<2) ;
SID TYPE LMODE REQUEST BLOCK
-------------- ---------- ---------- ----------
22 AE 4 0 0
22 TM 3 0 0
22 TX 6 0 0
AE是和版本化(Workspace Manager)相关的东西,这里不再过多描述。
从上面的查询结果可以看到更新的时候
会添加一个3级的表锁,也就是 row-X (SX)锁,保证在事务结束之前,表的结构不会被更改。多个事务可以同时持有相同表的sx锁。
还有一个6级的行锁,exclusive (X),保证在事务结束之前,相关的行信息不会被更改。(锁信息存放于block中)
ok简单示例后,来进行这一小节的主要内容,阻塞示例。
insert操作会对表加3级rx锁,和行排他锁,但是一般不会发生阻塞,因为读一致性的关系,在没提交之前只有当前session才可以操作新插入的行,对于其他事务来说 新增的记录是不可见的。
下面列举几种特殊的阻塞情况。
在11gr2中,可以使用insert /*+ append */ intoselect 的方式执行直接路径加载。
或者 insert /*+append_values */ into values 的方式。
这里使用第二种。
Session1session_id=22:
_dexter@FAKE>insert /*+ append_values */ into tun2_tab values (1) ;
1 rowcreated.
_dexter@FAKE>select sid , type , lmode , request , block from v$lock where sid = (select sidfrom v$mystat where rownum<2) ;
SID TYPE LMODE REQUEST BLOCK
-------------- ---------- ---------- ----------
22 AE 4 0 0
22 TM 6 0 0
22 TX 6 0 0
可以看到使用直接路径加载的时候会对表加6级排他锁。根据表1,它会阻塞所有试图在表上加锁的事务。
Session2session_id=24:
_dexter@FAKE>update tun2_tab set id=3 ;
waiting...
看一下锁的情况:
_sys@FAKE>select sid , type , id1 , lmode , request , block
2 from v$lock l
3 where sid in (select session_id from v$locked_object)
4 and type in ('TM', 'TX')
5 order by 1 ;
SID TYPE ID1 LMODE REQUEST BLOCK
-------------- ---------- ---------- ---------- ----------
22 TM 82618 6 0 1 --session1 包含了表6级锁,它正在阻塞其他的事务
22 TX 524296 6 0 0
24 TM 82618 0 3 0 --session2 它正在请求表的3级锁。
Session1
Session2
Description
T1
insert /*+ append_values */ into tun2_tab values (1) ;