什么是死锁
当一个会话A想要获得另一个会话B所持有的资源,但是会话B也想要获得会话A所持有的资源时就会出现死锁.
下面将演示一个死锁的例子:
jy@JINGYONG> insert into test_jy values(1,'First'); 已创建 1 行。 jy@JINGYONG> insert into test_jy values(2,'Second'); 已创建 1 行。 jy@JINGYONG> commit; 提交完成。 jy@JINGYONG> select rowid,num,txt from test_jy; ROWID NUM TXT ------------------ ---------- ---------- AAASNsAAEAAAAIlAAA 1 First AAASNsAAEAAAAIlAAB 2 Second session#1: SQL> update test_jy set txt='session1' where num=1; 1 row updated. session#2: jy@JINGYONG> update test_jy set txt='session2' where num=2; 已更新 1 行。 jy@JINGYONG> update test_jy set txt='session2' where num=1;
现在session#2正等待session#1所持有的TX锁
session#1:
SQL> update test_jy set txt='session1' where num=2;
现在session#1正等待这一行的TX锁,这个锁被session#2所持有,然而session#2也正等待session#1这就形成了死锁,当出现死锁时一个会话会抛出一个ORA-00060错误.
session#2:
* 第 1 行出现错误: ORA-00060: 等待资源时检测到死锁
这时session#1仍然被锁直接到session#2提交或回滚出错的ORA-00060的语句它只会回滚当前的语句而不是整个事务.
诊断信息由ora-00060提供
ora-00060错误通常会将错误信息写入alert.log文件并同时创建一个跟踪文件.跟踪文件会根据创建跟踪文件的进程的类型写入user_dump_dest或background_dump_dest目录中.
跟踪文件包含死锁图表信息和其它信息.
Deadlock graph: ---------Blocker(s)-------- ---------Waiter(s)--------- Resource Name process session holds waits process session holds waits TX-00030004-000002c7 22 26 X 24 29 X TX-00040014-0000022b 24 29 X 22 26 X session 26: DID 0001-0016-00000073 session 29: DID 0001-0018-000000BE session 29: DID 0001-0018-000000BE session 26: DID 0001-0016-00000073 Rows waited on: Session 26: obj - rowid = 0001236C - AAASNsAAEAAAAIlAAA (dictionary objn - 74604, file - 4, block - 549, slot - 0) Session 29: obj - rowid = 0001236C - AAASNsAAEAAAAIlAAB (dictionary objn - 74604, file - 4, block - 549, slot - 1) ----- Information for the OTHER waiting sessions ----- Session 29: sid: 29 ser: 94 audsid: 410112 user: 91/JY flags: 0x45 pid: 24 O/S info: user: oracle, term: UNKNOWN, ospid: 3753 image: oracle@jingyong (TNS V1-V3) client details: O/S info: user: oracle, term: pts/1, ospid: 3746 machine: jingyong program: sqlplus@jingyong (TNS V1-V3) application name: SQL*Plus, hash value=3669949024 current SQL: update test_jy set txt=:"SYS_B_0" where num=:"SYS_B_1" ----- End of information for the OTHER waiting sessions ----- Information for THIS session: ----- Current SQL Statement for this session (sql_id=b8gxacbadupu7) ----- update test_jy set txt=:"SYS_B_0" where num=:"SYS_B_1" =================================================== PROCESS STATE ------------- ....
第一部分:Deadlock graph
Deadlock graph: ---------Blocker(s)-------- ---------Waiter(s)--------- Resource Name process session holds waits process session holds waits TX-00030004-000002c7 22 26 X 24 29 X TX-00040014-0000022b 24 29 X 22 26 X session 26: DID 0001-0016-00000073 session 29: DID 0001-0018-000000BE session 29: DID 0001-0018-000000BE session 26: DID 0001-0016-00000073
这上面的信息显示了哪个进程持有的锁和哪个进程正等待的的锁资源的情况.对于每一个资源都有两部分信息与相关的进程相关联
Blockers(s)
Waiters(s)
在Deadlock graph中的信息
Resource Name:被持有或被等待的锁名称
Resource Name由三部分组成:Lock Type_ID1_ID2,ID1和ID2依赖于锁类型会有所不同
TX-00030004-000002c7
Lock Type:TX
ID1(00030004)和ID2(000002c7)指示回滚段和事务的事务表条目.
process 锁/等待会话的v$process.pid
session 锁/等待会话的v$session.sid
holds 持有的锁模式
waits 等待的锁模式
因此
sid 26(process 22)在排他模式下持有TX-00030004-000002c7锁并在排他模式下等待锁TX-00040014-0000022b
sid 29(process 24)在排他模式下持有TX-00040014-0000022b锁并在排他模式下等待TX-00030004-000002c7锁
最重要的是要注意对于每种资源的锁类型,模式的持有者和模式的请求指示了造成死锁的原因
第二部分:Rows waited on
Rows waited on: Session 26: obj - rowid = 0001236C - AAASNsAAEAAAAIlAAA (dictionary objn - 74604, file - 4, block - 549, slot - 0) Session 29: obj - rowid = 0001236C - AAASNsAAEAAAAIlAAB (dictionary objn - 74604, file - 4, block - 549, slot - 1)
如果死锁是由于以不同的顺序来获得行级锁造成的那么每个会话都正等待锁定自己的所持有的行源.如果请求的
TX模式 X等待那么’Rows waited on’可能是很有用的信息.而对于其它类型的锁’Rows waited on’通常会显示为”no row”
在上面的例子中
sid 26 was waiting for rowid ‘AAASNsAAEAAAAIlAAA’ of object 74604
sid 29 was waiting for rowid ‘AAASNsAAEAAAAIlAAB’ of object 74604
它们可能来检查实行的行记录:
jy@JINGYONG> select owner,object_name,object_type from dba_objects where object_ id=74604; OWNER OBJECT_NAME OBJECT_TYPE ------------------------------ ----------------------------- -------------- JY TEST_JY TABLE jy@JINGYONG> select * from test_jy where rowid='AAASNsAAEAAAAIlAAA'; NUM TXT ---------- ---------- 1 First
第三部分:Information for the OTHER waiting sessions
----- Information for the OTHER waiting sessions ----- Session 29: sid: 29 ser: 94 audsid: 410112 user: 91/JY flags: 0x45 pid: 24 O/S info: user: oracle, term: UNKNOWN, ospid: 3753 image: oracle@jingyong (TNS V1-V3) client details: O/S info: user: oracle, term: pts/1, ospid: 3746 machine: jingyong program: sqlplus@jingyong (TNS V1-V3) application name: SQL*Plus, hash value=3669949024 current SQL: update test_jy set txt='session1' where num=2; ----- End of information for the OTHER waiting sessions -----
这一部分显示了参与死锁的其它会话的信息,这些信息包括:
会话信息
客户端信息
当前的sql语句
update test_jy set txt=’session1′ where num=2;
第四部分:Information for THIS session
Information for THIS session: ----- Current SQL Statement for this session (sql_id=b8gxacbadupu7) ----- update test_jy set txt='session2' where num=1
显示了这个会话造成ora-00060错误的语句
避免死锁
上面死锁发生是因为程序没有限制行被更新的顺序引起的.程序可以避免行级死锁通过强制行更新的顺序例如使用下面的限制就不会发生死锁
Session #1: update test_jy set txt='session1' where num=1; Session #2: update test_jy set txt='session2' where num=1; > Session #2 is now waiting for the TX lock held by Session #1 Session #1: update test_jy set txt='session1' where num=2; > Succeeds as no-one is locking this row commit; > Session #2 is released as it is no longer waiting for this TX Session #2: update test_jy set txt='session2' where num=2; commit;
限制行被更新的顺序可以保证不会发生死锁.上面只是一个简单的产生死锁的情况.死锁不一定要是相同表之间的行,也可能是不同表中的行.因此最重要的是限制表更新的顺序和表中行被更新的顺序.
不同锁类型与模式
最常见的死锁类型是TX和TM锁.它们可能出现许多持有/请求模式.
锁模式 模式请求 可能的原因
TX X(mode 6) 程序行级冲突
通过重新编写程序确保行以特定的顺序被锁定
TX S(mode 4)
TM SSX(mode 5) 这通常与存在外键约束但在子表中没有在外键列上创建索引有关
或
S(mode 4)
TM锁
TM锁中的ID1指示了哪个对象正被锁定.这使得当TM锁发生时隔离与死锁相关的对象是非常容易的
TM锁的格式是TM-0001236C-00000000其中0001236C是对象编号的十六进制表示.
1.转换0001236c为十进制
0001236c的十进制是74604
2.定位对象
jy@JINGYONG> select owner,object_name,object_type from dba_objects where object_ id=74604; OWNER OBJECT_NAME OBJECT_TYPE ------------------------------ ----------------------------- -------------- JY TEST_JY TABLE
怎么样获得其它的信息
可以通过在init.ora文件中设置
event=”60 trace name errorstack level 3;name systemstate level 266″
或者通过alter system来设置这个事件
ALTER SYSTEM SET events’60 trace name errorstack level 3;name systemstate level 266′;
注意这个事件会生成很大的跟踪文件你要确保max_dump_file_size的值有足够大来生成跟踪文件