引言:Oracle 锁在我一开始接触的时候会有一种高深莫测的感觉,就像是遥远的外星人看不见摸不着但是能感觉到,我在实际的工作中就遇到过ORA-00054: resource busy acquire with nowait specified错误不能插入表,当时知道是被锁定了,根据V$LOCK也定位出[url=]阻塞[/url]的会话了,但不知道如何长久的解决它,究其原因就是不清楚内部机制与释放原理,下面根据例子来揭开锁的面纱,走进Oracle锁的世界。
分别模拟insert,update和delete造成阻塞的示例,并对v$lock中的相应的信息进行说明,给出[url=]SQL[/url]演示。
LEO1@LEO1> create user leo2 identified by leo2 default tablespace leo1; 新创建一个LEO2用户
User created.
LEO1@LEO1> grant connect,resource to leo2; 授予基本权限
Grant succeeded.
LEO1@LEO1> select owner,table_name,tablespace_name from dba_tables where wner='LEO1';
OWNER TABLE_NAME TABLESPACE_NAME
------------------------------ ------------------------------ ------------------------------
LEO1 LEO_WAGE LEO1
LEO1@LEO1> create [url=]table[/url] t1 (id int primary key); 创建t1表,设置id列为主键
Table created.
LEO1@LEO1> insert into t1 values(1);
1 row created.
LEO1@LEO1> select * from t1;
ID
----------
1
LEO2@LEO1> insert into leo1.t1 values(1); 当没有提交,在插入同样的values时就发生了对会话的阻塞,hang在这里不能前进
LEO1@LEO1> commit; 必须提交后,阻塞才终止,也就是说commit可以释放阻塞
Commit complete.
LEO2@LEO1> insert into leo1.t1 values(1); 因为已经有了1值,故违反了主键约束
insert into leo1.t1 values(1)
*
ERROR at line 1:
ORA-00001: unique constraint (LEO1.SYS_C0010817) violated
update 锁阻塞
LEO1@LEO1> select * from t1;
ID
----------
1
2
100
LEO1@LEO1> update t1 set id=200 where id=100; 更新一行没有提交,没有提交的事物对别人是不可见的,但在物理块上真真切切的修改了,他人只能访问undo回滚段中镜像
1 row updated.
LEO2@LEO1> update leo1.t1 set id=300 where id=100; 我们在会话leo2上也更新同一个表里的同一行,此时hang住了不动了,因为2个会话在争用同一条记录的修改权
LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where [url=]type[/url] in ('TM','TX') order by 1,2; 一般影响业务性能的就 TM and TX 锁
SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
138 TM 73449 0 3 0 0
138 TX 196615 912 6 0 1
156 TM 73449 0 3 0 0
156 TX 196615 912 0 6 0
SID:会话id号
TYPE:锁的类型
ID1:会话操作对象的id号
ID2:ID1+ID2 定位回滚段上的一个地址(即修改之前数据镜像地址),由于138和156会话是一样的说明指向的是同一个地址,换句话说操作的是同一行数据
LMODE:锁模式,不同的数字代表不同的锁模式 例如 0 现在没有申请到锁 3 共享锁模式(段级共享锁) 6 排他锁模式 锁的级别越高限制越多
REQUEST:目前会话没有锁,正在申请的锁模式 例如 0 没有正在申请的锁,说明已经有锁了 6 现在正在申请6号锁,目前因为没有才申请
BLOCK:当前正在阻塞几个会话 例如 1 当前正在阻塞一个会话 2 当前正在阻塞两个会话
锁的实质:是维护一个事务完整性的,锁的信息是数据块的一个属性,是物理的,并不是逻辑上属于某个表或者某几行的。
LEO1@LEO1> select distinct sid from v$mystat; 这个会话当前id是138,我们怎么区分呢?=> LEO1用户=138 LEO2用户=156
SID
----------
138
LEO1@LEO1> select object_name from dba_objects where object_id=73449; 138会话操作的对象是T1表
OBJECT_NAME
--------------------------------------------------------------------------------
T1
说明:138会话在T表上加了TM和TX锁,TM锁模式为3(共享锁) TX锁模式6(排他锁),目前TX锁正在阻塞一个会话(就是156会话)。
156 会话就是当前被阻塞的会话,156会话操作对象也是T1表(ID1都一样的),TM锁模式也为3(共享锁就是有几个会话就可以创建几个共享锁,同时存在),TX现在还没有申请到锁,正在申请6号锁,而这个6号锁就是138会话所持有的(因为2个会话操作的是同一行数据)
LEO1@LEO1> select sid,event from v$session_wait where sid in (138,156); 从会话等待视图上可以看出,有哪些会话由于什么原因导致等待事件不能前进
SID EVENT
---------- ----------------------------------------------------------------
138 SQL*Net message to client
156 enq: TX - row [url=]lock[/url] contention
156会话由于TX锁争用原因导致hang住不能前进,enq=enqueues队列锁(通常和业务有关,为了保护业务的锁)
小结:现在我们应该很晴朗的看出138会话阻塞156会话,以及阻塞的原因和会话数和锁类型
insert 锁阻塞
LEO1@LEO1> select * from leo1.t1;
ID
----------
1
2
200
LEO1@LEO1> insert into leo1.t1 values(3); 插入一行但没有提交,这是一个未决状态,还不清楚是否真正插入
1 row created.
LEO2@LEO1> insert into leo1.t1 values(3); 我们在会话leo2上也插入同样的数据,此时hang住了不动了,这里实际上是插入了2条独立的记录,不能认为是同一条记录,只是值一样
LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2;
SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
138 TM 73449 0 3 0 0
138 TX 65555 681 6 0 1 138正在阻塞另一个会话
156 TM 73449 0 3 0 0
156 TX 458766 669 6 0 0 这也显示了在插入第二条记录时没有被阻塞
156 TX 65555 681 0 4 0 而在插入的修改值相同后被阻塞了,锁的级别是4
insert 时v$lock视图里面多了一个TX锁(就是最后一行),首先说明一下insert和update delete 操作的不同,后两者都是对同一条记录的修改权争用产生阻塞(这里不涉及修改值的问题),而insert操作实际上插入了2条不同的记录,由于这2条不同的记录的修改值一样违反了主键约束从而产生阻塞,实际是对修改值的相同产生了阻塞。锁的级别为4,这种锁比update的锁级别要低,锁的级别越低限制越少。
delete 锁阻塞
LEO1@LEO1> select * from leo1.t1; t1表中有5条记录,我们计划删除的是最后1条
ID
----------
1
2
4
5
200
LEO1@LEO1> delete from leo1.t1 where id=200; 138会话正在删除id=200的记录,但是没有提交,此时就是加上一个TM TX锁
1 row deleted.
LEO2@LEO1> delete from leo1.t1 where id=200; 这时158会话也做同样的动作,就被hang住了不能动了,下面我们来看看锁定情况
LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2;
SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
138 TM 73449 0 3 0 0
138 TX 524316 935 6 0 1 138会话持有一个6级排他锁,正在阻塞一个会话
156 TM 73449 0 3 0 0
156 TX 524316 935 0 6 0 156会话被阻塞住了没有获得锁,正在申请一个6级锁
LEO1@LEO1> select object_name from dba_objects where object_id=73449; 现在可知锁定的就是t1表
OBJECT_NAME
--------------------------------------------------------------------------------
T1
LEO1@LEO1> select sid,event from v$session_wait where sid in (138,156); 从会话等待视图上也可以看出138阻塞了156会话
SID EVENT
---------- ----------------------------------------------------------------
138 SQL*Net message from client
156 enq: TX - row lock contention
156会话由于TX锁争用原因导致hang住不能前进,enq=enqueues队列锁
小结:我们在了解锁的同时,也要在业务设计的流程上尽量去避免它们的发生,比如说2个人的工作没有协调好,在同一时间去做了同一件事,这就有可能产生锁。
select...for update 锁阻塞 这是一种对结果集修改的保护机制
场景:一次性修改多条记录的时候会用到这个命令,起到锁定结果集的效果,这也是结果集修改引起的阻塞
LEO1@LEO1> select * from leo1.t1;
ID
----------
1
2
3
200
LEO1@LEO1> select * from leo1.t1 where id<=3 for update; 如果我们想对查询出的结果集进行独占,并且此时不允许其他会话进行修改,可以这么来写
ID
----------
1
2
3
LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2;
SID TYPE ID1 ID2 LMODE REQUEST BLOCK
---------- ---------- ---------- ---------- ---------- ---------- ----------
138 TM 73449 0 3 0 0
138 TX 589839 915 6 0 0 这3行记录都已经被TX锁锁定了,在没有提交之前别人不能修改
LEO2@LEO1> update leo1.t1 set id=4 where id=1;
LEO2@LEO1> update leo1.t1 set id=4 where id=2;
LEO2@LEO1> update leo1.t1 set id=4 where id=3; 我们在会话leo2上测试更新结果集中的每条记录,都会hang住了不能前进,说明这
个结果集已经整体被锁定
LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2;
SID TY ID1 ID2 LMODE REQUEST BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
138 TM 73449 0 3 0 0
138 TX 589839 915 6 0 1 138正在阻塞另一个会话
156 TM 73449 0 3 0 0
156 TX 589839 915 0 6 0
LEO1=138会话 LEO2=156会话,我们可以看出138会话阻塞156会话,156会话TX在请求一个6号排他锁,因为2个会话都在修改同一个结果集。这种方法可以一次性锁定n行记录。
重点:一个表上只能有一个6号锁
模拟RI锁定导致[url=]阻塞[/url]的场景,并分析v$lock相应的锁定信息,给出[url=]SQL[/url]演示。
LEO1@LEO1> create [url=]table[/url] a (id int primary key); a是主表,定义了id字段为主键
Table created.
LEO1@LEO1> create table b (id references a(id)); b是从表,id字段是引用主表的id字段
Table created.
LEO1@LEO1> insert into a values(1); 往主表a中插入一条数据但没有提交,事务没有结束会产生锁定
1 row created.
LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where [url=]type[/url] in ('TM','TX') order by 1,2;
SID TYPE ID1 ID2 LMODE REQUEST BLOCK
---------- ---------- ---------- ---------- ---------- ---------- ----------
138 TM 73465 0 3 0 0 insert由于有从属关系因此会在2个表上都加3号共享锁
138 TM 73467 0 3 0 0
138 TX 196640 940 6 0 0
LEO1@LEO1> select object_name from dba_objects where object_id in (73465,73467); ID1就是138会话操作的对象id,我们会在主表和从表上都加上表级锁
OBJECT_NAME
--------------------------------------------------------------------------------
A 73465
B 73467
LEO1@LEO1> commit; 提交之后释放锁
Commit complete.
LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2; 锁会随着事务的结束而释放
no rows selected
LEO1@LEO1> select * from a; a表中有一条记录
ID
----------
1
LEO1@LEO1> select * from b;
no rows selected
LEO1@LEO1> update a set id=100 where id=1; 主表a上更新了一条记录
1 row updated.
LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2;
SID TYPE ID1 ID2 LMODE REQUEST BLOCK
---------- ---------- ---------- ---------- ---------- ---------- ----------
138 TM 73465 0 3 0 0 update现在只对主表有锁定,从表没有锁定
138 TX 196634 941 6 0 0
LEO1@LEO1> commit; 提交之后释放锁
Commit complete.
LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2; 现在没有锁了
no rows selected
LEO1@LEO1> select * from a; 主表里的值已经更新了
ID
----------
100
LEO1@LEO1> delete from a;
1 row deleted.
LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2;
SID TYPE ID1 ID2 LMODE REQUEST BLOCK
---------- ---------- ---------- ---------- ---------- ---------- ----------
138 TM 73465 0 3 0 0 delete也是只对主表有锁定,从表没有锁定
138 TX 655375 705 6 0 0
LEO1@LEO1> commit; 提交释放锁
Commit complete.
LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2;
no rows selected
LEO1@LEO1> insert into b values(2);
insert into b values(2)
*
ERROR at line 1:
ORA-02291: integrity constraint (LEO1.SYS_C0010831) violated - parent key not found 直接给从表插入记录,如果主表没有的话,会报错违反引用完整性约束,没有主表依据
LEO1@LEO1> insert into a values(2); 我们只能先给主表插入
1 row created.
LEO1@LEO1> insert into b values(2); 再给从表插入才可以,因为从表的数据必须在主表里先存在,才能正常引用
1 row created.
LEO1@LEO1> select * from a; 主表有了
ID
----------
2
LEO1@LEO1> select * from b; 从表有了
ID
----------
2
LEO1@LEO1> select * from a; 主表有3
ID
----------
2
3
LEO1@LEO1> insert into b values(3); 才能给从表插入
1 row created.
LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2;
SID TYPE ID1 ID2 LMODE REQUEST BLOCK
---------- ---------- ---------- ---------- ---------- ---------- ----------
138 TM 73465 0 3 0 0 从表的insert也会对主从表同时加锁
138 TM 73467 0 3 0 0
138 TX 393246 939 6 0 0
LEO1@LEO1> select * from b;
ID
----------
2
3
LEO1@LEO1> commit; 释放锁
Commit complete.
LEO1@LEO1> delete from b; 删除从表
2 rows deleted.
LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2;
SID TYPE ID1 ID2 LMODE REQUEST BLOCK
---------- ---------- ---------- ---------- ---------- ---------- ----------
138 TM 73465 0 3 0 0 从表delete也会对主从表同时加锁
138 TM 73467 0 3 0 0
138 TX 196620 944 6 0 0
LEO1@LEO1> commit; 释放锁
Commit complete.
LEO1@LEO1> select * from a; 主表有2条记录
ID
----------
2
3
LEO1@LEO1> select * from b; 从表没有记录
no rows selected
LEO1@LEO1> insert into a values(4); 向主表插入1条记录,因为没有提交所以是未决状态
1 row created.
LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2;
SID TYPE ID1 ID2 LMODE REQUEST BLOCK
---------- ---------- ---------- ---------- ---------- ---------- ----------
138 TM 73465 0 3 0 0 此时对主从表都加了锁定
138 TM 73467 0 3 0 0
138 TX 589834 937 6 0 0
LEO2@LEO1> insert into leo1.b values(4); 此时向从表也插入1条记录,由于从表的数据必须引用自主表,而主表数据现在是一种未决状态,所以hang住不能前进
LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2;
SID TYPE ID1 ID2 LMODE REQUEST BLOCK
---------- ---------- ---------- ---------- ---------- ---------- ----------
138 TM 73465 0 3 0 0
138 TM 73467 0 3 0 0
138 TX 589834 937 6 0 1 138会话阻塞156会话,这个6代表已经插入成功,但修改值还是未决状态
156 TM 73467 0 3 0 0
156 TM 73465 0 3 0 0
156 TX 393221 942 6 0 0 这个6代表也已经插入成功,但修改值还是未决状态
156 TX 589834 937 0 4 0 主从表插入后产生了2个TX锁,这说明这是2条不同的记录,2个独立的记录,不是争用同一条记录
小结:之所以还有一个TX锁正在申请4号锁,是因为2条记录的修改值都是未决状态违反了引用完整性约束从而产生阻塞。导致156会话hang住不能前进。
自己构想一个使用手工锁定解决一种业务需求的场景,并给出[url=]SQL[/url]演示。
场景:手工锁定一个表,例如 我们在做一个秘密交易的时候,谈好的价格就不能变了,必须一手交钱一手交货完成交易,为了保证价格安全,我们先把价格表锁定,这期间不允许篡改,保证完成交易
LEO1@LEO1> [url=]lock[/url] [url=]table[/url] t1 in share mode; 手工锁定一个表,设置锁的级别为4
Table(s) Locked.
LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where [url=]type[/url] in ('TM','TX') order by 1,2;
SID TYPE ID1 ID2 LMODE REQUEST BLOCK
---------- ---------- ---------- ---------- ---------- ---------- ----------
138 TM 73449 0 4 0 0 已经在T1表上加上了4号锁,除了当前会话外[url=]阻塞[/url]其他会话进行修改
LEO2@LEO1> insert into leo1.t1 values(5); 我们在会话leo2上插入一条记录,此时hang住了不动了
LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2;
SID TYPE ID1 ID2 LMODE REQUEST BLOCK
---------- ---------- ---------- ---------- ---------- ---------- ----------
138 TM 73449 0 4 0 1
156 TM 73449 0 0 3 0
这就是由于我们加了4号锁除了当前会话外阻塞156会话进行修改,156会话默认可以获得一个3号锁,由于3号和4号互斥不能共存,所以没有获得锁,正在等待申请3号锁
LEO1@LEO1> commit; 锁跟着事务的结束而释放,commit rollback都行
LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2; 此时没有锁信息了
no rows selected
深入分析mode 2-6 的TM锁相互间的互斥关系
[url=]Oracle[/url] TM锁的类型 锁模式
| 锁描述
| 含义
| 锁定表的SQL
| 0
| None
|
|
| 1
| Null
| 空,本模式是oracle预留模式
|
| 2
| Row Share(RS) 又叫(SS)
| 行级共享锁,是限制最少的TM锁,可以提供最高程度的并发性。其他会话可以对锁定的表进行任何类型的DML操作,还可以与其他会话锁并存
| [url=]Lock[/url] table t in row share mode;
| 3
| Row Exclusive Table Lock(RX) 又叫(SX)
| 行级排他锁,通常已经有事务在修改行或者select…for update修改结果集。允许其他事务对锁定的表进行select insert update delete或lock table同时锁定一张表
| Lock table t in row exclusive mode;
| 4
| Share Table Lock(S)
| 共享锁,其他事务可以查询锁定的表但不能修改,只允许当前事务修改,但可以多个事务持有它
| Lock table t 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 t in exclusive mode;
|
Oracle锁模式互斥关系图 锁模式
| 锁名称
| 允许级别
| 互斥级别
| 2
| 行级共享锁
| 2 3 4 5
| 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
|
实验锁互斥 准备工作 LEO1@LEO1> select distinct sid from v$mystat; LEO1用户的会话id=138 SID ---------------------------- 138 LEO2@LEO1> select distinct sid from v$mystat; LEO2用户的会话id=156 SID ---------------------------- 156 LEO1@LEO1> create table lock1 (x int primary key); 创建lock1表,设置x列为主键 Table created. LEO1@LEO1> insert into lock1 values(1); 我们插入1 1 row created. LEO1@LEO1> commit; 提交 Commit complete. LEO1@LEO1> select * from lock1; 现在只有一条记录,并且没有锁 X ---------------------------- 1 LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2; no rows selected
行级共享锁Row Share(RS) 2
LEO1@LEO1>lock table lock1 in row share mode; 把lock1表设置为行级共享锁模式 Table(s) Locked. LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2; SID TYPE ID1 ID2 LMODE REQUEST BLOCK ---------- ---------- ---------- ---------- ---------- ---------- -------------------- ---------- ---------- ---------- ---------- ---------- -- 138TM 73472 0 2 0 0 模式标识:2 LEO1@LEO1> select object_name from dba_objects where object_id=73472; lock1表对象id为73472 OBJECT_NAME ---------------------------------------------------------------------------------------------------- LOCK1
LEO2@LEO1>insert into leo1.lock1 values(2); 1 row created. LEO2@LEO1> select * from leo1.lock1; X ---------- 1 2 LEO2@LEO1>delete from leo1.lock1 where x=1; 1 row deleted. LEO2@LEO1> select * from leo1.lock1; X ---------- 2 LEO2@LEO1>update leo1.lock1 set x=10 where x=2; 1 row updated. LEO2@LEO1> select * from leo1.lock1; X ---------- 10 LEO2@LEO1>select * from leo1.lock1 for update; X ---------- 10 LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2; SID TYPE ID1 ID2 LMODE REQUEST BLOCK ---------- ---------- ---------- ---------- ---------- ---------- -------------- ---------- ---------- ---------- ----------------- 138TM 73472 0 2 0 0 156TM 73472 0 3 0 0 156 TX 524321 936 6 0 0 小结:行级共享锁,是限制最少的TM锁,可以提供最高程度的并发性。其他会话可以对锁定的表进行任何类型的DML操作,还可以与其他会话锁并存。
行级排他锁 Row Exclusive Table Lock(RX) 3
LEO1@LEO1>lock table leo1.lock1 in row exclusive mode; 把lock1表设置为行级排他锁 Table(s) Locked. LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2; SID TYPE ID1 ID2 LMODE REQUEST BLOCK ---------- ---------- ---------- ---------- ---------- ---------- -------------------- ---------- ---------- -------------------- 138TM 73472 0 3 0 0 模式标识:3 3级锁是一个灵活性比较大的锁,insert delete update都可以产生一个3级锁,也允许其他事务来修改锁定的表 LEO1@LEO1>select * from leo1.lock1; X ----------------- 10 20 30 40 50 会话27 LEO1@LEO1>update leo1.lock1 set x=100 where x=10; 1 row updated. LEO1@LEO1> select * from leo1.lock1; 已经被修改了 X ------------------ 20 30 40 50 100 会话156 LEO2@LEO1>insert into leo1.lock1 values(60); 也已经插入了,注意没有提交的事务对别人是不可见的 1 row created. LEO2@LEO1> select * from leo1.lock1; X ----------------- 10 20 30 40 50 60 会话146 LEO2@LEO1>delete from leo1.lock1 where x=20; 已经删除 1 row deleted. LEO2@LEO1> select * from leo1.lock1; X -------------------- 10 30 40 50 LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2; SID TYPE ID1 ID2 LMODE REQUEST BLOCK ---------- ---------- ---------- ---------- ---------- ---------- ---------------- ---------- ---------- ---------------- ---------- 27TM 73472 0 3 0 0 27TX 327698 1144 6 0 0 138 TM 73472 0 3 0 0 146TM 73472 0 3 0 0 146TX 196626 975 6 0 0 156TM 73472 0 3 0 0 156TX 262163 782 6 0 0 大家都是共存的,谁也没有[url=]阻塞[/url]谁,block列全部是0 小结:行级排他锁,通常已经有事务在修改行或者select…for update修改结果集。允许其他事务对锁定的表进行select insert update delete或lock table同时锁定一张表。
共享锁 Share Table Lock(S) 4
LEO1@LEO1> select * from leo1.lock1; 还是有5条记录 X ----------------- 10 20 30 40 50 LEO1@LEO1>lock table leo1.lock1 in share mode; 把lock1表设置为共享锁 Table(s) Locked. LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2; SID TYPE ID1 ID2 LMODE REQUEST BLOCK ---------- ---------- ---------- ---------- ---------- ---------- -------------- ---------- ---------- ---------- ---------- ----- 138TM 73472 0 4 0 0 模式标识:4 4级锁禁止其他会话对锁定的表进行DML操作但可以select查询,还允许多个事物一起持有 LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2; SID TYPE ID1 ID2 LMODE REQUEST BLOCK ---------- ---------- ---------- ---------- ---------- ---------- ------------------ ---------- ---------- ------------------ ---- 13 TM 73472 0 0 4 0 27TM 73472 0 0 3 0 138 TM 73472 0 4 0 1 146TM 73472 0 0 3 0 156TM 73472 0 0 3 0 27 146 156会话都已经被阻塞了,有的朋友会问4级锁可以和4级锁共存这里为什么不行呢。呵呵因为有3级锁在捣乱,4级和3级是不能共存的,所以我们把所有的3级锁都释放就可以了,我们来看一下 LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2; SID TYPE ID1 ID2 LMODE REQUEST BLOCK ---------- ---------- ---------- ---------- ---------- ---------- -------------------- ---------- ---------- ---------- ---------- 13TM 73472 0 4 0 0 27TM 73472 0 2 0 0 138TM 73472 0 4 0 0 现在4级锁2级锁都可以同时存在了 小结:共享锁,其他事务可以查询锁定的表但不能修改,只允许当前事务修改,但可以多个事务持有它。
共享行级排他锁 Share Row Exclusive Table Lock(SRX) 5
LEO1@LEO1>lock table leo1.lock1 in share row exclusive mode; 把lock1表设置为共享行级排他锁 Table(s) Locked. LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2; SID TYPE ID1 ID2 LMODE REQUEST BLOCK ---------- ---------- ---------- ---------- ---------- ---------- ------------ ---------- ---------- ---------- ------------ ----- 138TM 73472 0 5 0 0 模式标识:5 LEO1@LEO1> select object_name from dba_objects where object_id=73472; 现在锁定的表就是lock1 OBJECT_NAME -------------------------------------------------------------------------------- LOCK1 会话138 LEO1@LEO1> select * from leo1.lock1; 现在表里有5条记录,我们看看其他会话能不能修改表 X -------------------- 10 20 30 40 50 会话156 LEO2@LEO1>insert into leo1.lock1 values(60); hang住了不能够前进说明被阻塞 会话27 LEO1@LEO1>update leo1.lock1 set x=100 where x=10; hang住了不能够前进说明被阻塞 会话146 LEO2@LEO1>delete from leo1.lock1 where x=20; hang住了不能够前进说明被阻塞 那么select… for update当然也会被阻塞的,我们来看看其他事务能不能查询呢! 会话23 LEO2@LEO1> select * from leo1.lock1; X ------------------- 10 20 30 40 50 LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2; SID TYPE ID1 ID2 LMODE REQUEST BLOCK ---------- ---------- ---------- ---------- ---------- ---------- ------------------- ---------- ------------------- ---------- - 27TM 73472 0 0 3 0 138 TM 73472 0 5 0 1 146TM 73472 0 0 3 0 156TM 73472 0 0 3 0 会话23没有被阻塞可以正常查询耶,这也验证了我们的观点,读操作不会被任何事务阻塞,也不会加锁,27 146 156会话3个行级排他锁都在等待着138会话释放锁 LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2; SID TYPE ID1 ID2 LMODE REQUEST BLOCK ---------- ---------- ---------- ---------- ---------- ---------- ---------- 13TM 73472 0 2 0 0 138TM 73472 0 5 0 0 会话13的2级锁和会话138的5级锁可以共存符合我们的锁互斥关系 小结:共享行级排他锁,同一时间只允许一个事务持有和修改锁定的表,其他事务可以查询但不能修改。
排他锁 Exclusive Table Lock (X) 6
LEO1@LEO1>lock table leo1.lock1 in exclusive mode; 把lock1表设置为排他锁,等级最高的锁 Table(s) Locked. LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2; SID TYPE ID1 ID2 LMODE REQUEST BLOCK ---------- ---------- ---------- ---------- ---------- ---------- -------------- ---------- ---------- -------------- ---------- 138TM 73472 0 6 0 0 模式标识:6 会话156 LEO2@LEO1>insert into leo1.lock1 values(60); 会话27 LEO1@LEO1>update leo1.lock1 set x=100 where x=10; 会话146 LEO2@LEO1>delete from leo1.lock1 where x=20; 会话13 LEO2@LEO1>lock table leo1.lock1 in row share mode; 测试锁互斥 LEO1@LEO1> select sid,type,id1,id2,lmode,request,block from v$lock where type in ('TM','TX') order by 1,2; SID TYPE ID1 ID2 LMODE REQUEST BLOCK ---------- ---------- ---------- ---------- ---------- ---------- ---------------- ---------- ---------- ---------- ---------- ------- 13TM 73472 0 0 2 0 27TM 73472 0 0 3 0 138 TM 73472 0 6 0 1 146TM 73472 0 0 3 0 156TM 73472 0 0 3 0 6级锁会阻塞除了自己外的所有会话的事务并且排斥其他的所有锁模式连2级锁都不行,是最高限制的TM锁,当然select还是没有问题的。 小结:排他锁,是限制最高的TM锁,禁止其他事务执行任何类型的DML语句或者锁表。一个表一般只能有一个6号锁。
|