oracle没有锁管理器和锁列表,这样可以避免行级锁维护的开销和行级锁数量不足导致的争用问题。在Oracle的每行数据上,都有一个标志位来表示该行数据是否被锁定,要查看某一行是否被锁定,必须直接找到这一行,而不要指望能从哪个列表得到答案,事务只是找到数据。其locking过程如下:
㈠ 找到想锁定的那一行的地址
㈡ 到达那一行
㈢ 锁定这一行
在这行的位置,而非某个锁列表。如果这一行已经锁定,则等待锁定它的事务结束,除非使用nowait选项。
保护元数据---->TM锁(表级锁)
保护数据 ---->TX锁(事务锁)
v$lock列:ID1、ID2
对TM锁,ID1表示被locking对象的object_id,ID2始终为0
对TX锁,ID1表示该事务的xidusn、xidslot,ID2表示xidsqn
对ID1的拆解:
14:14:56 hr@ORCL (^ω^) select id1,id2,type from v$lock where type='TX';
ID1 ID2 TYPE
---------- ---------- ----
524320 1748 TX
14:16:56 hr@ORCL (^ω^) select 524320/65536 xidusn,mod(524320,65536) xidslot from dual;
XIDUSN XIDSLOT
---------- ----------
8.00048828 32
事务锁不是行级锁。行级锁触发事务锁。一个事务只有一个事务锁,但可以有多个行级锁。TX锁用作一种排队机制:请求锁的事务会排队,等待目前持有锁的事务执行,然后得到数据。
事务中DML或select ...for update都会得到一个TX锁。
session 1:scott
SQL> update dept set dname=initcap(dname);
已更新4行。
SQL> select username,l.sid,trunc(id1/power(2,16)) xidusn,bitand(id1,to_number('ffff','xxxx'))+0 slot,
2 id2 sqn,lmode,request
3 from v$lock l,v$session s
4 where l.type='TX' and
5 l.sid=s.sid and
6 s.username=USER
7 /
USERNAME SID XIDUSN SLOT SQN LMODE REQUEST
---------- ---------- ---------- ---------- ---------- ---------- ----------
SCOTT 154 10 40 1395 6 0
SQL> select xidusn,xidslot,xidsqn from v$transaction;
XIDUSN XIDSLOT XIDSQN
---------- ---------- ----------
10 40 1395
注释:
① v$lock表中lmode=6为X锁(排他表级锁)。request=0则意味着你拥有这个锁
② oracle不会在任何地方存储行级锁列表。所以v$lock表只有一行,而不是四行
session 2:也是scott
SQL> update emp set ename=upper(ename);
已更新14行。
SQL> update dept set deptno=deptno-10;
现在会话被阻塞。
SQL> select username,l.sid,trunc(id1/power(2,16)) xidusn,bitand(id1,to_number('ffff','xxxx'))+0 slot,
2 id2 sqn,lmode,request
3 from v$lock l,v$session s
4 where l.type='TX' and
5 l.sid=s.sid and
6 s.username=USER
7 /
USERNAME SID XIDUSN SLOT SQN LMODE REQUEST
---------- ---------- ---------- ---------- ---------- ---------- ----------
SCOTT 135 10 40 1395 0 6
SCOTT 135 2 1 1777 6 0
SCOTT 154 10 40 1395 6 0
SQL> select xidusn,xidslot,xidsqn from v$transaction;
XIDUSN XIDSLOT XIDSQN
---------- ---------- ----------
2 1 1777
10 40 1395
这里可以看到一个新的事务,xid为(2,1,1777)。request=6表明对一个X锁的请求。请求行的xid正是持有
者的事务ID。
SQL> select (select username from v$session where sid=a.sid) blocker,a.sid,
2 'is blocking',
3 (select username from v$session where sid=b.sid) blockee,b.sid
4 from v$lock a,v$lock b
5 where a.block=1 and
6 b.request>0 and
7 a.id1=b.id1 and
8 a.id2=b.id2
9 /
BLOCKER SID 'ISBLOCKING' BLOCKEE SID
---------- ---------- ---------------------- -------- ----------
SCOTT 154 is blocking SCOTT 135
表级锁(table-level lock)的作用是对并发的 DDL 操作进行访问控制,例如防止在 DML 语句执行期间相关的表被移除。当用户对表执行 DDL 或 DML 操作时,将获取一个此表的表级锁。表级锁不会影响其他并发的 DML 操作。对于分区表来说,表级锁既可以针对整个表,也可以只针对某个分区。
当用户执行以下 DML 语句对表进行修改:INSERT,UPDATE,DELETE,及 SELECT ... FOR UPDATE,或执行 LOCK TABLE 语句时,事务将获取一个表级锁。当一个未提交的事务拥有某个表上的锁时,此表就无法被修改定义或被移除。
大家都知道TM锁共有6种模式,最常见的是3(插入,更新,删除);4(创建索引时);5(部分DDL操作如:删除列)等等
RS
行共享表级锁(row share table lock)(也称为 subshare table lock,SS)表明拥有此锁的事务已经锁定了表内的 某些数据行,并有意对数据行进行更新操作。当执行以下 SQL 语句时将获得表上的行共享表级锁:
SELECT ... FROM table ... FOR UPDATE OF ... ;
OR
LOCK TABLE table IN ROW SHARE MODE;
RS限制程度最低,因而能够保证表的最大的并发访问能力
查看本栏目更多精彩内容:http://www.bianceng.cn/database/Oracle/