create table eg_60 ( num number, txt varchar2(10) );
insert into eg_60 values ( 1, 'First' );
insert into eg_60 values ( 2, 'Second' );
SQL> select rowid, num, txt from eg_60;
ROWID NUM TXT
------------------ ---------- ----------
AAAQT2AAHAAAEdYAAA 1 First
AAAQT2AAHAAAEdYAAB 2 Second
Session1:
update eg_60 set txt='ses1' where num=1;
Session2:
update eg_60 set txt='ses2' where num=2;
update eg_60 set txt='ses2' where num=1;
update eg_60 set txt='ses1' where num=2;
此時Session2報的錯:
update eg_60 set txt='ses2' where num=1
*
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource
Session1的update eg_60 set txt='ses1' where num=2;仍處hang狀态,此時Session2執行exit正常退出,則
1 row updated.
原因就是正常退出,Oracle的PMON會自動rollback所做的未Commit操作,釋放了num=2的資源,是以Session1可以執行。
出現60錯誤會産生一個trace檔案,檢視trace檔案位置:
show parameter user_dump
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
user_dump_dest string /opt/app/ora10g/admin/petest/udump
檢視trace檔案:
Deadlock graph:
---------Blocker(s)-------- ---------Waiter(s)---------
Resource Name process session holds waits process session holds waits
TX-00090004-00019887 25 478 X 24 459 X
TX-000a002d-00032a8d 24 459 X 25 478 X
session 478: DID 0001-0019-00027AEC session 459: DID 0001-0018-000CDDD8
session 459: DID 0001-0018-000CDDD8 session 478: DID 0001-0019-00027AEC
Rows waited on:
Session 459: obj - rowid = 000104F6 - AAAQT2AAHAAAEdYAAB
(dictionary objn - 66806, file - 7, block - 18264, slot - 1)
Session 478: obj - rowid = 000104F6 - AAAQT2AAHAAAEdYAAA
(dictionary objn - 66806, file - 7, block - 18264, slot - 0)
Information on the OTHER waiting sessions:
Session 459:
pid=24 serial=34722 audsid=899246 user: 65/DCSOPEN
O/S info: user: dcsopen, term: pts/0, ospid: 8838, machine: vm-vmw4131-t
program: sqlplus@vm-vmw4131-t (TNS V1-V3)
application name: SQL*Plus, hash value=3669949024
Current SQL Statement:
update eg_60 set txt='ses1' where num=2
End of information on OTHER waiting sessions.
Current SQL statement for this session:
===================================================
這裡66806代表的OBJECT_ID對應object是eg_60。目前執行的SQL是update eg_60 set txt='ses2' where num=1,是這條SQL報的60錯誤,原因是由于update eg_60 set txt='ses1' where num=2這條SQL。因為這裡是在同一台機器開的兩個session,如果是不同機器用戶端通路資料庫做的這個實驗,就可以根據machine: vm-vmw4131-t知道是哪個用戶端執行的這條SQL。
通過PROCESS STATE節中O/S info: user: dcsopen, term: pts/1, ospid: 13112, machine: vm-vmw4131-t也可以知道是哪個用戶端執行SQL報的60錯誤。
以上是同一張表不同session之間産生的死鎖。還有另外一種場景,也是之前這邊應用碰到的問題,即不同表之間的死鎖,剛剛初步得解的,其實上述兩種都屬于事務級别的死鎖,這裡可能說的不準确,就是因為執行一個SQL後沒有commit或rollback,再執行另外一個SQL,這兩個SQL形成一個事務,造成可能的死鎖。
關于事務,Concept中的解釋:
A transaction is a logical unit of work that contains one or more SQL statements. A transaction is an atomic unit. The effects of all the
SQL statements in a transaction can be either all committed (applied to the database) or all rolled back (undone from the database).
A transaction begins with the first executable SQL statement. A transaction ends when it is committed or rolled back, either explicitly
with a COMMIT or ROLLBACK statement or implicitly when a DDL statement is issued.
比如:
UPDATE TABLE1,UPDATE TABLE2 ...
DELETE TABLE2, DELETE TABLE1 ...
此時碰巧可能出現互相持有對方需要的資源,導緻deadlock。
對于這種情況,可能的解決方法就是:将表的順序改為一緻,或者拆分更小的事務,避免較差更新的情況。
另外,對于批量更新,和上面一個事務中多個表操作的原理相同,并發大則也會導緻deadlock。要麼減少并發,要麼不用批量更新。其實出現deadlock,此時報錯的SQL會自動執行rollback,但注意這裡是語句級rollback,即隻會rollback出錯的SQL,之前的SQL不會rollback,是以上述第一個例子中Session2中的SQL報錯,但Session1中的第二條SQL仍舊處于hang狀态,除非Session2中對應的資源釋放。