一、锁类型
按类型分,可分为排他锁(X锁)和共享锁(S锁)。
排他锁:如果一个对象被加了X锁,在这个锁被采用commit或rollback释放之前,该对象上不能施加任何其它类型的锁。
共享锁:如果一个对象被施加了S锁,该对象上可以再加其他类型的S锁,但是,在该锁释放之前,该对象不能被加任何其它类型的X锁。
按照锁定的对象来分,可分为DML锁、DDL锁与内存锁(latch)。[@more@]一、锁类型
按类型分,可分为排他锁(X锁)和共享锁(S锁)。
排他锁:如果一个对象被加了X锁,在这个锁被采用commit或rollback释放之前,该对象上不能施加任何其它类型的锁。
共享锁:如果一个对象被施加了S锁,该对象上可以再加其他类型的S锁,但是,在该锁释放之前,该对象不能被加任何其它类型的X锁。
按照锁定的对象来分,可分为DML锁、DDL锁与内存锁(latch)。
1、DML锁
1)TX锁,事务锁,当一个事务数据更新,如insert、update、delete、merge或者select … for update的时候,会对所操作的行产生一个TX锁,直到这个事务被commit或rollback。
Oracle的TX锁是行级别的,但可以一次性锁定多行,行锁的标志被记录在数据块上。
在数据行上不存在S锁。
2)TM锁,可以是手工的lock命令,或者是DML及select … for update的时候加在表对象上的锁,可以防止其他对象对表结构加X类型的锁(如变更表结构、truncate、drop等)。
TM锁分五个级别,对应于v$lock中的LMODE字段:
2(RS,row share)、3(RX,row exclusive)、4(S,share)、5(SRX,share row exclusive)、6(X,exclusive)。
DML操作表数据的时候,是先加TM锁,如果能加上,才再加TX锁。
例如:DML和select … for update都是先在表上加RX锁,然后再在修改的数据行上加TX锁。
TM锁除了DML语句外,还可以通过lock table命令来加锁:
Lock table table_name in row share mode; -- 加RS锁,只不允许X锁,和同一行上的RX
Lock table table_name in row exclusive mode; -- 加RX锁,允许不同行的RS和RX锁
Lock table table_name in share mode; -- 加S锁,允许RS和S锁
Lock table table_name in share row exclusive mode; -- 加SRX锁,只允许RS锁
Lock table table_name in exclusive mode; -- 加X锁,都不允许
DML和select for update加RX锁允许RS和RX锁再存在,所以一个表上面可以加多个RX锁,可以并发DML。
在一个会话中,TX锁一般只有一个,因为只有一个事务,TX是对应的事务锁;而TM锁可以有多个,因为在一个会话中,可能更新多个表。
2、DDL锁
Oracle的DDL语句,类似于下面的伪代码:
Begin
commit;
DDL语句
commit;
Exception
when others then rollback;
end;
因为DDL总是提交,所以,操作DDL的时候,需要注意是否不小心提交了本会话的其他事务。
(小心DDL之前的未提交DML事务在DDL回退时被自动提交。)
eg:
Session1
Delete from a where a=1;
Session2
Delete from a;
Session1
Truncate table a;
ERROR at line 1:
ORA-00054:resource busy and acquire with NOWAIT specified
DDL锁主要有两类:
1)X类型的DDL,排他类型的DDL,多发生在truncate,drop,alter table drop/add/modify等绝大部分DDL上面。这样的语句也会在操作期间给表加一个X(独占)类型的TM锁。
2)S类型的DDL,如online操作,会在表上加一个RS类型的TM锁,因为RS类型的锁是可以再加RX锁的,所以online操作不阻塞DML语句。
Eg1:
Alter table test drop column owner;期间,在另一个会话上查询这个会话的锁类型,发现这个DDL在表上加的TM锁是级别为5的SRX锁,这个级别的锁只能允许最低级别的RS锁在表上出现,即会阻止DML和DDL操作。
eg2:
会话1:
Create index ind_test1 on test(object_id);
会话2:
Select sid,type,id1,id2,lmode from v$lock where sid=1005;可看到,建索引时在TEST表上加的是级别为4的S锁,这个锁也阻塞RX锁,影响DML的正常使用。
如果采用online方式创建索引,则不同:
会话1:
Create index ind_test1 on test(object_id) online;
会话2:
Select sid,type,id1,id2,lmode from v$lock where sid=1005;可看到,在online建索引的时候,在TEST表上加的是最低级别的RS锁(级别为2),允许建索引的同时DML操作。
以online方式创建索引时,将产生一个中间的日志表,在其上加级别为4的TM锁,而在主表上加级别为2的RS锁,故它对主表的操作没有任何影响。
3、内存锁(Latch)
是一个运行在内存中,保护内存结构的轻量级的锁。如果处理得不好,将耗费大量的cpu来管理内存锁,较为典型的就是硬分析。
Runstats_pkg包,用来对比两次不同的执行所耗费的资源。
二、阻塞
1、TX阻塞
会话1:
Select * from test where a=100 for update;
会话2:
Update test set b=100 where a=100;--被阻塞
查看这两个会话的锁类型:
Select sid,type,lmode,request,block from v$lock where sid in(150,160);
sid TY LMODE REQUEST BLOCK
-----------------------------------------------------
150 TX 0 6 0
160 TM 3 0 0
150 TM 3 0 0
160 TX 6 0 1
2、TM阻塞
会话1:
用lock table table_name in share mode来模拟表创建索引。
Lock table test in share mode;
会话2:
Update test set b=100 where a=100;
阻塞。
3、Latch阻塞
TX与TM阻塞不会阻塞select语句,因为select语句并不在表上加任何锁,所以也不会被阻塞,而且,根据oracle特有的一致性读规则,select将保证获得一致性的数据。
而latch却可以阻塞select,如Library cache lock等待,典型的例子就是大表建约束:
在一个大表上面创建一个唯一/主键约束,此时oracle会自己创建索引。但是因为创建约束导致oracle的这个表对象的属性变化,而如果创建索引的时间又很长,将导致select语句阻塞在library cache lock上,不能获得表的句柄(handle)信息,所以不能分析该语句,更不用说执行(select)该语句了。
会话1:(SID=160)
Select count(*) from test where rownum
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/86728/viewspace-1008882/
,如需转载,请注明出处,否则将追究法律责任。