关于锁
1、TX锁(事务锁)
create table test2 as select * from gwm_attribute where rownum<5;
select * from test;
update test2 set gwm_ano=gwm_ano+10;
--如果有一个更新行没有提交或回滚,执行如下语句就会看到一个lmode为6,request为0的排他锁;如果在另一个会话中又对这个表执行更新,
--就会陷入死锁,再执行如下语句就会看到出现两行记录,其中的lmode为0,request为6的就是一个请求排他锁的请求,如果阻止该会话的排他锁提交
--或回滚,这个请求行就会消失。
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 = 'GWM';

select xidusn,xidslot,xidsqn from v$transaction;

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;
--提交原来的事务(sid=145),并重新运行锁出现,请求行就消失了。

create语句的两个物理参数
initrans:这个结构的初始预分配大小。默认为2
maxtrans:这个结构可以扩缩的最大大小。默认为255.但是在oracle 10g中这个设置已经废弃了,在oracle10g中只要块上的空间足够,
即使设置了maxtrans,oracle也会不受约束地扩大事务表。若是在oracle9i或之前的版本,一旦达到maxtrans值,事务表就不会再扩大了。
如:
create table t1 (x int) maxtrans 2;
insert into t1 select rownum from all_users;
select distinct dbms_rowid.rowid_block_number(rowid) from t;

--在该会话中执行如下语句
update t set x=1 where x=1;
--在另一个会话中执行如下语句
update t set x=2 where x=2;
--在又另一个会话中执行如下语句
update t set x=3 where x=3;
发现都可以顺利更新,因为oracle10g尽管在设置时将maxtrans设为2,但是maxtrans始终为255。如果是在之前的版本,就会发现到第三个会话的时候
就会出现锁定状态

2、TM(DML Enqueue)锁
该锁用于确保在修改表的内容时,表的结构不会改变。
如果已经有一个TM锁,另一用户试图在这个表上执行DDL,就会得到如下错误。
drop table t2
error at line 1:
ora-00054:resource busy and acquire with nowait specified

create table t1 (x int);
create table t2 (x int);

insert into t1 values(1);
insert into t2 values(1);

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);

select object_name,object_id from user_objects where object_name in ('T1','T2');
--尽管每个事务只能得到一个TX锁,但是TM锁则不同,修改了多少个对象,就能得到多少个TM锁。而且TM锁的ID1列就是DML锁定对象的对象ID

3、DDL锁
三个类型
1)排他DDL锁
alter table t1 add new_column date;
在执行这个语句时,表t1不能被别人修改。在此期间,可以使用select查询这个表,但是大多数其他操作都不允许执行,包括所有DDL语句。在oracle中,
现在有些DDL操作没有DDL锁也可以发生。如:
create index t_idx on t1(x) online;
online 关键字会改变具体建立索引的方法。oracle并不是加一个排他DDL锁来防止数据修改,而只会试图得到表上的一个低级(mode2)TM锁。这会有效
防止其他DDL发生,同时还允许DML正常允许。

2)共享DDL锁
:在创建 存储的编译对象时,会对依赖的对象加这种共享DDL锁。如:
create view myview as select * from emp,dept where emp.deptno=dept.deptno;
表emp和dept上都会加共享DDL锁,而create view命令仍在处理。可以这些表的内容,但是不能修改它们的结构。

3)可中断解析锁
:你的回话解析一条语句时,对于该语句引用的每一个对象都会加一个解析锁。
dba_ddl_locks(如果该视图没有安装,可以通过以sys的身份执行D:\oracle\product\10.2.0\db_1\RDBMS\ADMIN该目录的catblock.sql脚本)

select session_id sid,owner,name,type,mode_held held,mode_requested request from dba_ddl_locks;
为看到一个实际的可中断的解析锁,下面先创建并运行存储过程p:
create or replace procedure p as begin null;end;
exec p
执行p过程后,过程p会出现在dba_ddl_locks视图中。即有这个过程的一个解析锁:
select session_id sid,owner,name,type,mode_held held,mode_requested request from dba_ddl_locks;
对该存储过程进行编译后在执行查询视图:编译后再查询该视图发现该p过程不在这个视图中了。--必须在sqlplus中执行,在plsql执行得不到这个结果。
alter  procedure p compile;
select session_id sid,owner,name,type,mode_held held,mode_requested request from dba_ddl_locks;

闩(latch)
:也是一种锁
latch“自旋”的问题:即当latch不是立即可用的,我们就得等待,在一台多cpu机器上,我们的会话就会自旋(spin),即在循环中反复地尝试来得到latch
。出现自旋的原因:上下文切换的开销很大,所以进程不能立即得到latch,我们就会一直待在cpu上,并立即再次尝试,而不是先睡眠,放弃cpu,
等到必须调度回cpu时才再次尝试。
latch的开销很大,对于不使用绑定变量与绑定变量的语句相比,消耗的时间,cpu都要多得多。

手动锁定和用户自定义锁
手动锁定:
通过select...for update语句来手动锁定数据
或者通过使用lock table语句手动锁定。这个语句很少使用,因为锁的粒度大,它只是锁定表,而不是锁定行。

创建自己的锁:
通过dbms_lock包。如可以利用该包,在打开、写入和关闭文件之前,可以采用排他模式请求一个锁,一次只能有一个人向这个文件写消息。这样所有人都会排队。

posted on 2011-01-10 14:36  蓝紫  阅读(1486)  评论(0编辑  收藏  举报