Oracle死鎖產生的緣由和解決辦法

若是有兩個會話,每一個會話都持有另外一個會話想要的資源,此時就會發生死鎖。
用下面實驗來講明死鎖的產生緣由和解決辦法。
SESSION1:
SQL> create table t2 as select * from emp;
SQL> select * from t2 where empno=7369;

     EMPNO ENAME      JOB              MGR HIREDATE                 SAL       COMM     DEPTNO
---------- ---------- --------- ---------- ----------------- ---------- ---------- ----------
      7369 SMITH      CLERK           7902 19801217 00:00:00        800                    20

SQL> update t2 set sal=sal+200 where empno=7369;

SQL> select * from t2 where empno=7369;

     EMPNO ENAME      JOB              MGR HIREDATE                 SAL       COMM     DEPTNO
---------- ---------- --------- ---------- ----------------- ---------- ---------- ----------
      7369 SMITH      CLERK           7902 19801217 00:00:00       1000                    20

SESSION2:

SQL> select * from t2 where empno=7900;

     EMPNO ENAME      JOB              MGR HIREDATE                 SAL       COMM     DEPTNO
---------- ---------- --------- ---------- ----------------- ---------- ---------- ----------
      7900 JAMES      CLERK           7698 19811203 00:00:00        950                    30

SQL> update t2 set sal=sal+200 where empno=7900;

1 row updated.

SQL> select * from t2 where empno=7900;

     EMPNO ENAME      JOB              MGR HIREDATE                 SAL       COMM     DEPTNO
---------- ---------- --------- ---------- ----------------- ---------- ---------- ----------
      7900 JAMES      CLERK           7698 19811203 00:00:00       1150                    30

SESSION1:
SQL> select * from t2 where empno=7900;

     EMPNO ENAME      JOB              MGR HIREDATE                 SAL       COMM     DEPTNO
---------- ---------- --------- ---------- ----------------- ---------- ---------- ----------
      7900 JAMES      CLERK           7698 19811203 00:00:00        950                    30

SESSION2:
SQL> select * from t2 where empno=7369;

     EMPNO ENAME      JOB              MGR HIREDATE                 SAL       COMM     DEPTNO
---------- ---------- --------- ---------- ----------------- ---------- ---------- ----------
      7369 SMITH      CLERK           7902 19801217 00:00:00        800                    20

SESSION1:
SQL> update t2 set sal=sal-200 where empno=7900; 
出現等待

SESSION2:
SQL> update t2 set sal=sal-200 where empno=7369;
死鎖發生,session2被阻塞
系統回滾session1跟死鎖有關的sql。
update t2 set sal=sal-200 where empno=7900
       *
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource

SESSION1:
SQL> select * from t2 where empno in (7369,7900);

     EMPNO ENAME      JOB              MGR HIREDATE                 SAL       COMM     DEPTNO
---------- ---------- --------- ---------- ----------------- ---------- ---------- ----------
      7369 SMITH      CLERK           7902 19801217 00:00:00       1000                    20
      7900 JAMES      CLERK           7698 19811203 00:00:00        950                    30
看到系統只回滾了對empno=7900的修改。
而此時SESSION2的update t2 set sal=sal-200 where empno=7369;依然被SESSION1的第一條語句所阻塞。


咱們如今查看產生鎖的狀況
打開第三個會話以DBA身份登陸
SQL> select * from v$lock;

ADDR     KADDR           SID TY        ID1        ID2      LMODE    REQUEST      CTIME      BLOCK
-------- -------- ---------- -- ---------- ---------- ---------- ---------- ---------- ----------
29434224 29434238        165 XR          4          0          1          0       2998          0
29434280 29434294        165 CF          0          0          2          0       2988          0
294342DC 294342F0        167 PW          1          0          3          0       2980          0
29434338 2943434C        165 RS         25          1          2          0       2983          0
294343F0 29434404        166 RT          1          0          6          0       2983          0
2943444C 29434460        153 TX     589868        325          0          4         24          0
29434560 29434574        167 MR          1          0          4          0       2983          0
294345BC 294345D0        167 MR          2          0          4          0       2983          0
29434618 2943462C        167 MR          3          0          4          0       2983          0
29434674 29434688        167 MR          4          0          4          0       2983          0
294346D0 294346E4        167 MR          5          0          4          0       2983          0
2943472C 29434740        167 MR          6          0          4          0       2983          0
29434788 2943479C        167 MR          7          0          4          0       2983          0
294347E4 294347F8        167 MR        201          0          4          0       2983          0
2943489C 294348B0        164 TS          3          1          3          0       2979          0
288F6030 288F6048        144 TM      53257          0          3          0         51          0
288F60DC 288F60F4        153 TM      53257          0          3          0         24          0
28934170 28934194        153 TX     655363        241          6          0         24          0
28969404 28969428        144 TX     589868        325          6          0         51          1

19 rows selected.

用下面的SQL語句能夠直接得出誰阻塞誰
SQL> select ( select username from v$session where sid=a.sid) blocker, a.sid,
        ' is blocking ',
        (select username from v$session where sid=b.sid) blockee, b.sid
from v$lock a, v$lock b
where a.block=1 and b.request>0 and a.id1=b.id1 and a.id2=b.id2;


BLOCKER                               SID 'ISBLOCKING'  BLOCKEE                               SID
------------------------------ ---------- ------------- ------------------------------ ----------
STONE                                 144  is blocking  STONE                                 153


發生死鎖的時候會在alert文件裏記錄下信息。
--查看操做系統下$ORACLE_BASE/admin/orcl/bdump/alert_orcl.log文件,會找到以下信息
Thu Sep  2 20:41:25 2010
ORA-00060: Deadlock detected. More info in file /u01/app/oracle/admin/orcl/udump/orcl_ora_4945.trc.

再查看跟蹤文件詳細信息
*** 2010-09-02 20:41:25.700
*** ACTION NAME () 2010-09-02 20:41:25.699
*** MODULE NAME (SQL*Plus) 2010-09-02 20:41:25.699
*** SERVICE NAME (SYS$USERS) 2010-09-02 20:41:25.699
*** SESSION ID (144.3) 2010-09-02 20:41:25.699
DEADLOCK DETECTED ( ORA-00060 )
[Transaction Deadlock]
The following deadlock is not an ORACLE error. It is a
deadlock due to user error in the design of an application
or from issuing incorrect ad-hoc SQL. The following
information may aid in determining the deadlock:
Deadlock graph:
                       ---------Blocker(s)--------  ---------Waiter(s)---------
Resource Name          process session holds waits  process session holds waits
TX-00090015-00000146        19     144     X             23     148           X
.......

SESSION2還在被SESSION1阻塞,只有在SESSION1執行提交或回退才能讓SESSION2繼續下去。
SESSION1:
commit; --將提交update t2 set sal=sal+200 where empno=7369的修改

rollback;--將取消update t2 set sal=sal+200 where empno=7369的修改

隨即SESSION2獲得1 row updated.的信息。

咱們也能夠用管理員帳號執行kill命令殺死致使阻塞的會話SESSION1來解決死鎖。
sqlplus / as sysdba
從上面查過的信息能夠知道產生阻塞的sid=144
經過查v$session視圖能夠得出serial#

SADDR           SID    SERIAL#     AUDSID PADDR         USER# USERNAME       COMMAND    OWNERID TADDR
-------- ---------- ---------- ---------- -------- ---------- ----------- ---------- ---------- -----
29F0BED4        144          3     210009 29E24174         64 STONE                0 2147483644

殺死這個會話用下面的命令
alter system kill session '144,3';

總結:
    Oralce認爲死鎖是應用致使的錯誤,Oracle中不多出現死鎖。致使死鎖的的頭號殺手是外鍵沒有加索引,第二號殺手則是位圖索引遭到併發更新。
    若是外鍵沒有索引,咱們更新了父表的主鍵時將會鎖住整個子表。若是外鍵沒有索引,刪除了父表中的一行,整個子表也會被鎖住。這樣就很容易產生不少問題,若是其中任何阻塞的會話鎖住了某一會話須要的資源就會出現一個死鎖。至於位圖索引的併發更新,是會鎖住全部相關聯的行,也會致使問題的發生。
    在Oracle9i及以上版本中,這些全表鎖都是短時間的,也就是僅在DML操做期間存在,而不是存在於整個事務期間。html

本文轉自:http://www.itpub.net/thread-1347577-1-1.htmlsql

相關文章
相關標籤/搜索