6.锁类型
DML锁
1> TX锁(事务锁)
1)定义:事务发起第一个修改时会得到TX锁(事务锁),而且会一直持有这个锁,直至事务执行提交或回滚。
2)作用:TX锁用作一种排队机制,使得其他会话可以等待这个事务执行。
3)Oracle中,闩为数据的一个属性,Oracle并没有一个传统的锁管理器,不会用锁管理器为系统中锁定的每一行维护一个长长的列表(其他许多数据库是这样做的,对于这些数据库来说,锁是一种稀有资源,使用太多就会出问题。)
4)Oracle的锁定过程:1.找到想锁定的那一行的地址;2.到达那一行;3.锁定这一行(如果该行已经锁定,则等待锁住它的事务结束,除非使用了NOWAIT选项)。
5)在 Oracle 中对数据行锁定时,行指向事务 ID 的一个副本,事务 ID 存储在包含数据的块中,释放锁时,事务 ID 却会保留下来。这个事务 ID 是事务所独有的,表示了回滚段号、槽和序列号。事务 ID 留在包含数据行的块上,可以告诉其他会话:你“拥有”这个数据(并非块上的所有数据都是你的,只是你修改的那一行“归你所有”) 。另一个会话到来时,它会看到锁 ID,由于锁 ID 表示一个事务,所以可以很快地查看持有这个锁的事务是否还是活动的。如果锁不活动,则允许会话访问这个数据。如果锁还是活动的,会话就会要求一旦释放锁就得到通知。因此,这就有了一个排队机制:请求锁的会话会排队,等待目前拥有锁的事务执行,然后得到数据。
7)视图V$LOCK中字段type,id1,id2的解释:
TYPE有TM,TX两种类型,TX为行级锁,事物锁,TM锁为表级锁
TYPE | ID1 | ID2 |
TM | 被修改表的标识(object_id) | 0 |
TX | 以十进制数值表示该事务所占用的回滚段号与该事务在该回滚段的事务表(Transaction table)中所占用的槽号(slot number,可理解为记录号)。其组成形式为:0xRRRRSSSS ( RRRR = RBS number, SSSS = slot )。 | 以十进制数值表示环绕(wrap)次数,即该槽(slot)被重用的次数; |
6)例:使用以下3个V$表:1.V$TRANSACTION:对应每个活动事务都包含一个条目;2.V$SESSION:显示已经登录的会话;3.V$LOCK:对应持有所有enqueue队列锁以及正在等待锁的会话,都分别包含一个条目(并不是说,对于表中被会话锁定的每一行,这个视图中就有相应的一行。)
首先启动一个事务:
update dept set deptno = deptno+10;
4 rows updated.
使用如下脚本查看此时系统的状态:
select username,
v$lock.sid,
trunc(id2/power(2,16)) rbs,
bitand(id1,to_number('ffff','xxxx'))+0 slot,
id2 seq,
lmode,
request
from v$lock,v$session
where v$lock.type = 'TX'
and v$lock.sid = v$session.sid
and v$session.username = USER;
USERNAME SID RBS SLOT SEQ LMODE REQUEST
----------- ------ ---- ------- ------ -------- ----------
SYS 155 9 18 760 6 0
select XIDUSN,XIDSLOT,XIDSQN from v$transaction;
XIDUSN XIDSLOT XIDSQN
---------- ---------- ----------
9 18 760
说明:1.LMODE=6是一个排他锁,REQUEST=0则意味着你没有发出请求,即你拥有这个锁;2.一个误解是认为V$LOCK中会有4行,因为我们锁定了4行。不过,要记住,Oracle不会在任何地方存储行级锁的列表(即:不会为每一个被锁定的行维护一个主列表)。要查看某一行是否被锁定,必须直接找到这一行;3.Oracle需要保存3个16位的数,但是对此只有两个列(ID1和ID2),其中ID1保存这其中两个数(回滚段号和槽号),用trunc(id1/power(2,16))获得回滚段号,用bitand(id1,to_numb er('ffff','xxxx'))+0把高位屏蔽获得槽号。4.RBS(回滚段号)、SLOT(槽号)和SEQ(ID2)组成了事务ID,与V$TRANSACTION信息匹配。
使用同样的用户名启动另一个会话,更新EMP中的某些行,并试图更新DEPT:
update emp set ename = upper(ename);
14 rows updated.
SQL> update dept set deptno = deptno-10;
此时,该会话阻塞,再次运行上面的脚本查询系统状态,结果如下:
USERNAME SID RBS SLOT SEQ LMODE REQUEST
---------- ---------- --- ------ ------ -------- ----------
SYS 128 9 18 760 0 6
SYS 128 5 3 810 6 0
SYS 155 9 18 760 6 0
XIDUSN XIDSLOT XIDSQN
---------- ---------- ----------
5 3 810
9 18 760
说明:可以看到开始了一个新事务,事务ID是(5,3,810)。这个新会话(128)在V$LOCK中有两行:一行表示它所拥有的锁(LMODE=6);另外一行的REQUEST=6,表示这是一个对排他锁的请求。该请求行的RBS/SLOT/SEQ值正是锁持有者的事务ID。SID=155的事务阻塞了SID=128的事务。
提交原来的事务(SID=155),再查询状态,结果如下:
USERNAME SID RBS SLOT SEQ LMODE REQUEST
---------- ------- ----- ----- ------ -------- ----------
SYS 128 5 3 810 6 0
说明:可以看到,另一个会话一旦放弃锁,请求行就会消失。这个请求就是排队机制,一旦事务执行,数据库会唤醒被阻塞的会话。
7)数据库块的最前面有一个“开销”空间,这里会存放该块的一个事务表,对于锁定了该块中某些数据的各个“实际”事务,在这个事务表中都有一个相应的条目。该结构的大小由创建对象时CREATE语句上的两个物理属性参数决定:INITRANS,该结构初始的预分配大小,对于索引和表,默认为2;MAXTRANS,在Oracle10g中,该设置已经被废弃,它的值总是255。
2> TM(DML Enqueue)锁
1)作用:TM锁用于确保在修改表的内容时,表的结构不会变化。例如,如果你已经更新了一个表,会得到该表的一个TM锁。这会防止另一个用户在该表上执行DROP或ALTER命令。
2)例:
首先创建表t1和t2:
create table t1(x int);
create table t2(x int);
insert into t1 values(1);
insert into t2 values(1);
使用以下脚本查看TM锁:
select (select username
from v$session
where sid = v$lock.sid) username,
sid,
id1,
id2,
lmode,
request,block,v$lock.type
from v$lock
where sid = (select sid
from v$mystat
where rownum=1)
/
USERNAME SID ID1 ID2 LMODE REQUEST BLOCK TY
---------- ------- ---- ---- -------- -------- ---- ---
SYS 155 62967 1 3 0 0 TO
SYS 155 99 0 4 0 0 AE
SYS 155 71191 0 3 0 0 TM
SYS 155 71192 0 3 0 0 TM
SYS 155 327690 811 6 0 0 TX
select object_name,object_id
from user_objects
where object_name in('T1','T2');
OBJECT_NAME OBJECT_ID
---------------------- ----------
T1 71191
T2 71192
说明:尽管每个事务只能得到一个TX锁,但是TM锁则不同,修改了多少个对象,就能得到多少个TM锁。其中,TM锁的ID1列就是锁定对象的对象ID。所以,很容易发现哪个对象持有这个锁。
3)系统中允许的TM锁总数可以由你来配置,这个数可能设置为0,但这并不是说你的数据库变成了一个只读数据库(没有锁),而是说不允许DDL。
4)通过使用ALTER TABLE TABLENAME DISABLE TABLE LOCK命令,可以逐对象禁用TM锁,起到两点作用:1.使意外删除表的“难度更大”,因为在删除前必须重新启用表锁;2.可以用它来检测由于外键未加索引而导致的全表锁。
例:作用一
create table p(x int primary key);
alter table p disable table lock;
drop table p;
drop table p
*
ERROR at line 1:
ORA-00069: cannot acquire lock -- table locks disabled for P
alter table p enable table lock;
drop table p;
Table dropped.
作用二
create table p(x int primary key);
insert into p values(1);
insert into p values(2);
create table c(x int references p);
insert into c values(1);
alter table c disable table lock;
update p set x=x+1 where x=2;
update p set x=x+1 where x=2
*
ERROR at line 1:
ORA-00069: cannot acquire lock -- table locks disabled for C
alter table c enable table lock;
update p set x=x+1 where x=2;
1 row updated.
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/17014649/viewspace-609610/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/17014649/viewspace-609610/