锁(lock)是用于防止在访问相同的资源(包括用户对象、系统对象、内存、Oralce数据字典中的共享数据结构,最常见的是数据库表Table对象)时 ,事务之间的有害性 交互(存、取)的一种机制。
不同类型的锁,代表了当前用户是允许还是阻止其它用户对相同资源的同时存取,从而确保不破坏系统数据的完整性、一致性和并行性。
锁的分类
DML锁:SELECT、INSERT、UPDATE、DELETE、MERGE操作
DDL锁:CREATE和ALTER语句操作
内部锁和闩:Oracle使用这些锁来包含内部数据结构,例如:Oracle查询生成的执行计划,执行计划会保存在库缓存中,当使用这个执行计划时,会对其加一个闩(latch)
DML锁
用于确保一次只能一个人修改某行数据。而且你正常处理这个表时,别人不能删除这个表。
TX锁,事务发起第一个修改时,会得到一个TX锁(事务锁),而且会一直持有这个事务,直到事务结束(COMMIT或者ROLLBACK)。事务中修改或者select for update的每一行都会指向该事务的TX锁。
TM锁,用于确保在修改表内容时,表的结构不被改变。
下面举例说明
登录到scott用户,并确定session id
SQL> grant select any dictionary to scott;
Grant succeeded.
SQL> conn scott/tiger
SQL> select sid from v$mystat where rownum=1;
SID
----------
37
SQL>
另开启一个会话,监控锁的使用情况
SQL> set linesize 200
SQL> select * from v$lock where sid=37;
ADDR KADDR SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK
---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ----------
0000000090D8FC88 0000000090D8FCE0 37 AE 100 0 4 0 481 0
SQL>
会话1执行更新操作
SQL> update emp set ename=initcap(ename);
14 rows updated.
会话2查看结果
SQL> /
ADDR KADDR SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK
---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ----------
0000000090D8FC88 0000000090D8FCE0 37 AE 100 0 4 0 944 0
00007FF9EEDA4AB0 00007FF9EEDA4B10 37 TM 87108 0 3 0 3 0
000000008F673658 000000008F6736D0 37 TX 131074 908 6 0 3 0
多了一个事务锁,一个TM锁。
会话1中再执行另一个表的更新操作
SQL> update dept set dname=initcap(dname);
4 rows updated.
会话2查看结果
SQL> /
ADDR KADDR SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK
---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ----------
0000000090D8FC88 0000000090D8FCE0 37 AE 100 0 4 0 1174 0
00007FF9EEDA7B58 00007FF9EEDA7BB8 37 TM 87108 0 3 0 233 0
00007FF9EEDA7B58 00007FF9EEDA7BB8 37 TM 87106 0 3 0 27 0
000000008F673658 000000008F6736D0 37 TX 131074 908 6 0 233 0
事务锁没有变,但是又多了一个TM锁。
对于TM锁来说,id1的值是对象的ID
SQL> COL OBJECT_NAME FOR A30
SQL> select OBJECT_NAME,OBJECT_ID from dba_objects where owner='SCOTT' AND OBJECT_NAME IN ('DEPT','EMP');
OBJECT_NAME OBJECT_ID
------------------------------ ----------
DEPT 87106
EMP 87108
对于TX锁,id1是通过事务id转换来的。
我们先查看下事务的相关信息
SQL> SELECT addr,xidusn,xidslot,xidsqn FROM V$TRANSACTION;
ADDR XIDUSN XIDSLOT XIDSQN
---------------- ---------- ---------- ----------
000000008F673658 2 2 908
ADDR与TX锁的ADDR对应,XIDUSN表示回滚段编号,XIDSLOT表示事务表上的编号,XIDSQN表示sequence(覆盖次数)
TX锁的id1的值等于XIDUSN*power(2,16)+XIDSLOT
SQL> select 2*power(2,16)+2 from dual;
2*POWER(2,16)+2
---------------
131074
事务表、回滚块、事务槽 三者之间的关系如下:
下面我们将dept的数据块dump出,查看块的详细信息
SQL> select dbms_rowid.rowid_relative_fno(rowid) fno,dbms_rowid.rowid_block_number(rowid) bno from dept;
FNO BNO
---------- ----------
4 135
4 135
4 135
4 135
只占用了一个数据块,将该块dump
SQL> alter system dump datafile 4 block 135;
System altered.
SQL> SELECT d.VALUE
|| '/'
|| LOWER (RTRIM (i.instance, CHR (0)))
|| '_ora_'
|| p.spid
|| '.trc'
trace_file_name
FROM (SELECT p.spid
FROM v$mystat m, v$session s, v$process p
WHERE m.statistic 2 3 4 5 6 7 8 9 10 # = 1 AND s.sid = m.sid AND p.addr = s.paddr) p,
(SELECT t.instance
FROM v$thread t, v$parameter v
WHERE v.name = 'thread'
AND (v.VALUE = 0 OR t.thread# = TO_NUMBER (v.VALUE))) i,
(SELECT VALUE
11 12 13 14 15 16 FROM v$parameter
WHERE name = 'user_dump_dest') d; 17
TRACE_FILE_NAME
--------------------------------------------------------------------------------
/u01/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_5593.trc
查看trace文件
Block header dump: 0x01000087
Object id on Block? Y
seg/obj: 0x15442 csc: 0x00.fab7a itc: 2 flg: E typ: 1 - DATA
brn: 0 bdba: 0x1000080 ver: 0x01 opc: 0
inc: 0 exflg: 0
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x0009.002.00000364 0x00c167b0.009a.2e C--- 0 scn 0x0000.000e0ef0
0x02 0x0002.002.0000038c 0x00c00591.0088.26 ---- 4 fsc 0x0000.00000000
bdba: 0x01000087
data_block_dump,data header at 0x7f23e518ea64
===============
tsiz: 0x1f98
hsiz: 0x1a
pbl: 0x7f23e518ea64
76543210
flag=--------
ntab=1
nrow=4
frre=-1
fsbo=0x1a
fseo=0x1f3c
avsp=0x1f22
tosp=0x1f22
0xe:pti[0] nrow=4 offs=0
0x12:pri[0] offs=0x1f7e
0x14:pri[1] offs=0x1f68
0x16:pri[2] offs=0x1f54
0x18:pri[3] offs=0x1f3c
block_row_dump:
tab 0, row 0, @0x1f7e
tl: 26 fb: --H-FL-- lb: 0x2 cc: 3
col 0: [ 2] c1 0b
col 1: [10] 41 63 63 6f 75 6e 74 69 6e 67
col 2: [ 8] 4e 45 57 20 59 4f 52 4b
tab 0, row 1, @0x1f68
tl: 22 fb: --H-FL-- lb: 0x2 cc: 3
col 0: [ 2] c1 15
col 1: [ 8] 52 65 73 65 61 72 63 68
col 2: [ 6] 44 41 4c 4c 41 53
tab 0, row 2, @0x1f54
tl: 20 fb: --H-FL-- lb: 0x2 cc: 3
col 0: [ 2] c1 1f
col 1: [ 5] 53 61 6c 65 73
col 2: [ 7] 43 48 49 43 41 47 4f
tab 0, row 3, @0x1f3c
tl: 24 fb: --H-FL-- lb: 0x2 cc: 3
col 0: [ 2] c1 29
col 1: [10] 4f 70 65 72 61 74 69 6f 6e 73
col 2: [ 6] 42 4f 53 54 4f 4e
end_of_block_dump
End dump data blocks tsn: 4 file#: 4 minblk 135 maxblk 135
的flag为空,表示没有提交,所以该行被锁定了(当然我们开需要查看事务表中的提交标志)。
2)Lck=4 表示锁定了4行数据。
锁的mode有如下几种
SQL> conn scott/tiger
Connected.
SQL> update dept set dname=lower(dname);
4 rows updated.
会话2,执行如下操作
SQL> conn scott/tiger
Connected.
SQL> update emp set ename=lower(ename);
14 rows updated.
SQL> update emp set ename=lower(ename);
此时会话1被阻塞。
会话2,执行对dept表的更新
SQL> update dept set dname=lower(dname);
此时会话2也被阻塞,但是会话1会报一个死锁的错误
SQL> update emp set ename=lower(ename);
update emp set ename=lower(ename)
*
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource
会话1需要提交或者回滚,会话2才能正常执行。
Oracle的死锁问题实际上很少见,如果发生,基本上都是不正确的程序设计造成的,经过调整后,基本上都会避免死锁的发生。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。