- Lock type(1)
参考TOM - expert oracle database
- Overview
- TX locks: 一个数据修改的事务需要获得TX lock.
- TM lock和DDL lock:这种锁用于保证数据对象的结构不被修改. TM是在修改对象的内容时获得,而DDL是在修改对象的本身.
- Lock的分类
- DML锁
- 在 select, update, insert, delete, merge时需要,主要包括TX和TM锁. 允许数据并发更改, dml时锁住特殊行数据或者在表级别上锁住每个行.
- DDL锁:create, alter object时需要,主要用于保护数据的结构.
- Internal锁和latches
- DML锁
- DML锁:用于保证两件事(上面提到的两种锁),一个防止同时修改1行,一个防止修改对象内容时对象本身被alter(如drop).
- TX(Transaction) Locks:
事务锁是在事务的第一个改变发生的时候获得,事务结束释放. 每个修改的行或者select for update的行都会指向那个事务关联的TX锁.
这个代价看起来高其实不然.
oracle中锁是数据的一部分,而传统的数据库锁的实现是基于内存的lock manager: 锁资源是有限的,每个锁住的行保存在一个长链表中.
传统:获得要锁定的行地址-->放到lock manager中排队-->锁住list-->遍历该list中该行是否已被锁定-->没有则新建一entry in list来确认已锁住-->unlock list.
当commit时,再次排队-->lock list-->遍历并且释放你的锁-->unlock list
传统方式成本很高,
oracle呢,不需要lock manager建立额外的list object:
找到要改的行的地址-->到该行-->锁住行
具体内部的实现参见:
http://www.360doc.com/content/061201/11/15284_279199.html
记录的行头中包含lb标识,指向一个itl(事务槽),空则表示该记录没有被修改过.
1)修改过之后,记录的lb标识(锁或者事务)指向一个itl,该itl的lock标识为1 表示该事务锁定了一条记录,flag为空表示该事务没有提交(是active session),提交后,其他不变(lb,lck),只有flag变为U(提交)
2)一个session请求lock时,同样去看lb,然后到itl看,如果不是active的,则去更新itl,lb. 如果是active,则等待,在enqueue lock fixed array中建立等待对象(按照lock时间顺序排序).同时设置time-out时间(到了会自动醒来查查状态).
3)Active会话commit后,修改flag,并且检查enqueue队列,通知那个等待时间最久的会话激活.
-此段类似与tom说的,比tom更底层直接一些. Transaction ID的含义-回滚的...
- TX(Transaction) Locks:
- Overview
select username,
v$lock.sid,
trunc(id1/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 = 'U1';
USERNAME SID RBS SLOT SEQ LMODE REQUEST
1 U1 154 9 24 429 6 0
在v$transaction中验证一下:
select XIDUSN, XIDSLOT, XIDSQN
from v$transaction;
XIDUSN XIDSLOT XIDSQN
1 9 24 429
session1中
update t1 set salary=salary+100 where id=3;
session2中
update t1 set salary=salary+100 where id=2;
session1中再运行session2的row update,阻塞等待...
update t1 set salary=salary+100 where id=2;
查询锁
USERNAME SID RBS SLOT SEQ LMODE REQUEST
1 U1 154 1 6 370 0 6
2 U1 139 1 6 370 6 0
3 U1 154 9 24 429 6 0
会话1拥有回滚段9-24-429(也就是事务ID),等待的是1-6-370(而该事务正在被139会话2使用)
查询事务
XIDUSN XIDSLOT X IDSQN
1 1 6 370
2 9 24 429
确认了一下只有两个active seesion..
用sql查询requestor和holder(v$lock中自查询)
select
(select username from v$session where sid=a.sid) blocker,
a.sid,
' is blocking ',
(select username from v$session where sid=b.sid) blockee,
b.sid
from v$lock a, v$lock b
where a.block = 1
and b.request > 0
and a.id1 = b.id1
and a.id2 = b.id2;
BLOCKER SID 'ISBLOCKING' BLOCKEE SID
1 U1 139 is blocking U1 154
commit会话2
锁信息
USERNAME SID RBS SLOT SEQ LMODE REQUEST
1 U1 154 9 24 429 6 0
而且,无论该事务中锁定了多少行记录,只需要该锁1把(而不是1行一把),这是因为内部结构的实现-每个块中记录事务(包含事务是否active和lock状态),而每行记录则指向该事务.
SQL> update t1 set salary=salary+200;
3 rows updated.
查询TX锁,仍然只有一条.
USERNAME SID RBS SLOT SEQ LMODE REQUEST
1 U1 149 2 46 495 6 0
另外参考: