首页 > 代码库 > 从浅到深掌握Oracle的锁
从浅到深掌握Oracle的锁
SQL> select * from t1;
ID
1
2
3
4
SQL> alter table t1 add primary key(id);
表已更改。
SQL> select * from v$lock where type in (‘TX‘,‘TM‘);
未选定行
SQL> insert into t1 values(5);
已创建 1 行。
SQL> select sid,type,id1,id2,lmode,request,block from v$lock where type in (‘TX‘,‘TM‘);
SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
141 TM 82975 0 3 0 0
141 TX 131084 1787 6 0 0
会话二:
SQL> insert into t1 values(5);
__
(阻塞)
会话一:
SQL> select sid,type,id1,id2,lmode,request,block from v$lock where type in (‘TX‘,‘TM‘);
SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
19 TX 131084 1787 0 4 0
(此处出现申请4号锁,insert本身没有阻塞,而是在等待判断主键冲突否)
19 TM 82975 0 3 0 0
141 TM 82975 0 3 0 0
19 TX 327697 1662 6 0 0
141 TX 131084 1787 6 0 1
SQL> update t1 set id=5 where id=4;
已更新 1 行。
SQL> select sid,type,id1,id2,lmode,request,block from v$lock where type in (‘TX‘,‘TM‘);
SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
141 TM 82975 0 3 0 0
141 TX 327706 1663 6 0 0
SQL> select sid from v$mystat where rownum=1;
SID
141
SQL> select sid,event from v$session_wait where sid in(141,19);
SID EVENT
---------- ----------------------------------------------------------------
19 SQL*Net message from client
141 SQL*Net message from client
会话二:
SQL> select sid from v$mystat where rownum=1;
SID
19
SQL> update t1 set id=5 where id=4;
__(阻塞)
会话一:
SQL> select sid,event from v$session_wait where sid in(141,19);
SID EVENT
---------- ----------------------------------------------------------------
19 enq: TX - row lock contention(等待事件出现tx锁,原因是行锁争用)
141 SQL*Net message from client
SQL> select sid,type,id1,id2,lmode,request,block from v$lock where type in (‘TX‘,‘TM‘);
SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
19 TX 327706 1663 0 6 0
(可以看到会话二在申请6号锁,而141的TX锁block为1,表示阻塞了别的会话)
19 TM 82975 0 3 0 0
141 TM 82975 0 3 0 0
141 TX 327706 1663 6 0 1
SQL> delete t1 where id=4;
已删除 1 行。
SQL> select sid,type,id1,id2,lmode,request,block from v$lock where type in (‘TX‘,‘TM‘);
SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
141 TM 82975 0 3 0 0
141 TX 327706 1663 6 0 0
SQL> select sid from v$mystat where rownum=1;
SID
141
SQL> select sid,event from v$session_wait where sid in(141,19);
SID EVENT
---------- ----------------------------------------------------------------
19 SQL*Net message from client
141 SQL*Net message from client
会话二:
SQL> select sid from v$mystat where rownum=1;
SID
19
SQL> delete t1 where id=4;
__(阻塞)
会话一:
SQL> select sid,event from v$session_wait where sid in(141,19);
SID EVENT
---------- ----------------------------------------------------------------
19 enq: TX - row lock contention(等待事件出现tx锁,原因是行锁争用)
141 SQL*Net message from client
SQL> select sid,type,id1,id2,lmode,request,block from v$lock where type in (‘TX‘,‘TM‘);
SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
19 TX 327706 1663 0 6 0
(可以看到会话二在申请6号锁,而141的TX锁block为1,表示阻塞了别的会话)
19 TM 82975 0 3 0 0
141 TM 82975 0 3 0 0
141 TX 327706 1663 6 0 1
KADDR
SID:锁所在的会话id
TYPE:锁的类型,类型有很多种,常用的有TX(事务锁)、TM锁(表级锁)
ID1:TM锁为对象的object_id,TX锁为v$transaction 中 XIDUSN * 2^16 + XIDSLOT
ID2:TM锁为0,TX锁为v$transaction 中 XIDSQN
LMODE:锁的模式,有2~6,越大锁的限制越高,
REQUEST:为0表示没有申请锁,其他2~6表示在申请该模式的锁
CTIME:表示锁从出现到现在的时间
BLOCK:为1表示阻塞了其他会话申请锁,为0表示没有阻塞别人。
会话一:
SQL> lock table t1 in share mode;
表已锁定。
会话二:
SQL> update t1 set id=11 where id=1;
__(等待)
直到会话一commit或roll,会话二执行。
锁模式 | 锁描述 | 含义 | 锁定表的SQL |
0 | None | ||
1 | Null | 空,本模式是oracle预留模式 | |
2 | Row Share(RS) 又叫(SS) | 行级共享锁,是限制最少的TM锁,可以提供最高程度的并发性。其他会话可以对锁定的表进行任何类型的DML操作,还可以与其他会话锁并存 | Lock table t1 in row share mode; |
3 | Row Exclusive Table Lock(RX) 又叫(SX) | 行级排他锁,通常已经有事务在修改行或者select…for update 修改结果集。允许其他事务对锁定的表进行select insert update delete 或 lock table 同时锁定一张表 | Lock table t1 in row exclusive mode; |
4 | Share Table Lock(S) | 共享锁,其他事务可以查询锁定的表但不能修改,只允许当前事务修改,但可以多个事务持有它 | Lock table t1 in share mode; |
5 | Share Row Exclusive Table Lock(SRX) 又叫SSX | 共享行级排他锁,同一时间只允许一个事务持有和修改锁定的表,其他事务可以查询但不能修改 | Lock table t in share row exclusive mode; |
6 | Exclusive Table Lock (X) | 排他锁,是限制最高的TM锁,禁止其他事务执行任何类型的DML语句或者锁表 一个表一般只能有一个6号锁 | Lock table t1 in exclusive mode; |
锁模式 | 锁名称 | 允许级别 | 互斥级别 |
2 | 行级共享锁 | 2 3 4 5 6 | 6 |
3 | 行级排他锁 | 2 3 | 4 5 6 |
4 | 共享锁 | 2 4 | 3 5 6 |
5 | 共享行级排他锁 | 2 | 3 4 5 6 |
6 | 排他锁 | 2 3 4 5 6 |
1、NULL,可以某些情况下,如分布式数据库的查询会产生此锁。
2、SS,表结构共享锁
3、SX,表结构共享锁+被操作的记录的排它锁
4、S, 表结构共享锁+所有记录共享锁
5、SRX 表结构共享锁+所有记录排它锁
6、X 表结构排它锁+所有记录排它锁
2 SS, 表结构共享+加上部分数据共享.虽然有人说,ORACLE里,数据没有S状态,但我还是愿意这 样理解:第1个S代表表结构共享,第2个代表表里的数据共享. 你可以想象一下,当往子表里增 加纪录时,主表的相关主键是不是得处于共享模式.
3 SX, 用于DML操作,第1个S代表表结构共享,第2个代表表里被操作的数据独占.
4 S, 代表表结构+表里的数据都是处于共享模式.当对表创建索引时,在创建期间,表处于这种模式.
5 SRX=S(4)+SX(3),
6 X, 删除表是会用上.
表已锁定。
141> select sid,type,id1,id2,lmode,request,block from v$lock where type in (‘TX‘,‘TM‘);
SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
141 TM 82975 0 2 0 0
19> select * from t1 for update; //另开会话给t1上3和6号锁
ID
----------
1
2
3
4
141> select sid,type,id1,id2,lmode,request,block from v$lock where type in (‘TX‘,‘TM‘);
SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
19 TM 82975 0 3 0 0
141 TM 82975 0 2 0 0
19 TX 393221 1754 6 0 0
可以看到236可以共存,没有互斥
19> lock table t1 in share mode; //给表再上4号锁
表已锁定。
141> select sid,type,id1,id2,lmode,request,block from v$lock where type in (‘TX‘,‘TM‘);
SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
19 TM 82975 0 5 0 0
141 TM 82975 0 2 0 0
19 TX 393221 1754 6 0 0
因为3和4不能共存,因此3+4升级为5号锁
19> lock table t1 in exclusive mode; //给表上6号锁,发生等待
__
141> select sid,type,id1,id2,lmode,request,block from v$lock where type in (‘TX‘,‘TM‘);
SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
19 TM 82975 0 5 6 1
141 TM 82975 0 2 0 1
19 TX 393221 1754 6 0 0
因为同是19号会话,上6号TM只需将原有5升级,但是已经存在2号TM,产生互斥,所以等待
表已锁定。
SQL> select sid,type,id1,id2,lmode,request,block from v$lock where type in (‘TX‘,‘TM‘);
SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
141 TM 82975 0 6 0 0
SQL> update t1 set id=5 where id=4;
已更新 1 行。
SQL> select sid,type,id1,id2,lmode,request,block from v$lock where type in (‘TX‘,‘TM‘);
SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
141 TM 82975 0 6 0 0
141 TX 262155 1324 6 0 0
表已锁定。
141> select sid,type,id1,id2,lmode,request,block from v$lock where type in (‘TX‘,‘TM‘) order by 1;
SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
141 TM 82975 0 2 0 0
19> update t1 set id=6 where id=4;
已更新 1 行。
141> select sid,type,id1,id2,lmode,request,block from v$lock where type in (‘TX‘,‘TM‘);
SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
19 TM 82975 0 3 0 0
141 TM 82975 0 2 0 0
19 TX 458778 1387 6 0 0
会话一:
SQL> update t1 set id=11 where id=1;
已更新 1 行。
会话二:
SQL> update t2 set id=11 where id=1;
已更新 1 行。
会话一:
SQL> update t2 set id=11 where id=1;
__(等待)
会话二:
SQL> update t1 set id=11 where id=1;
__(等待)
会话一:
SQL> update t2 set id=11 where id=1;
update t2 set id=11 where id=1
*
第 1 行出现错误:
ORA-00060: 等待资源时检测到死锁
从浅到深掌握Oracle的锁