oracle鎖問題模擬實驗

1.行級死鎖。
1.1主鍵、唯一索引的死鎖(會話交叉插入相同的主鍵值)
a.新建一張表,設置主鍵(或創建唯一索引)後插入一個值,然後不要COMMIT,另一個會話插入另一個值,也不要COMMIT,然後再把這兩個插入的值互相交換一下,在兩個會話中分別插入,死鎖就會產生。
在這裏插入圖片描述
因爲過程簡單,直接上圖了,我以scott用戶開了會話。1會話建表t_deadlock,插入第一條數據不提交,此時在2會話中插入第二條,不提交。再繼續插入1會話中對應值。模擬產生的阻塞。

b.PLSQL下查詢:

SELECT NVL(A.SQL_ID, A.PREV_SQL_ID) SQL_ID,

       A.BLOCKING_SESSION,

       A.SID,

       A.SERIAL#,

       A.LOGON_TIME,

       A.EVENT

  FROM GV$SESSION A

 WHERE A.SID IN (20,74)

 ORDER BY A.LOGON_TIME;

在這裏插入圖片描述
可以看到2的會話BLOCKING(阻塞)了sid20的會話。

c.此時在1會話中繼續插入2會話第一次插入的值,模擬死鎖。
在這裏插入圖片描述
如圖:2會話報ORA-00060 deadlock。

d.繼續查阻塞情況。
在這裏插入圖片描述
e.查alert日誌
在這裏插入圖片描述
f.查trc文件
在這裏插入圖片描述
Oracle對於死鎖有自己的內部處理機制會。當看到trace文件時,需要確認一下產生鎖的類型,是兩行還是一行,是TX還是TM,如果只有一行那麼說明是同一個SESSION,可能是自治事務引起的死鎖。

g.繼續提交2會話
在這裏插入圖片描述
會話2執行提交後,會話1就會報錯,違反唯一約束。這裏體現了ORACLE解除死鎖。9I以後Oracle檢查到60錯誤,會自動解鎖,並記錄trace。
附圖
在這裏插入圖片描述
1.2 外鍵的死鎖(外鍵未加索引)
外鍵未加索引很容易導致死鎖。在以下兩種情況下,Oracle在修改父表後會對子表加一個全表鎖:

  1. 如果更新了父表的主鍵,由於外鍵上沒有索引,所以子表會被鎖住。

  2. 如果刪除了父表中的一行,由於外鍵上沒有索引,整個子表也會被鎖住。
    總之,就是更新或者刪除父表的主鍵,都會導致對其子表加一個全表鎖。
    外鍵的死鎖可以這樣通俗的理解:有兩個表A和B:A是父表,B是子表。如果沒有在B表中的外鍵加上索引,那麼A表在更新或者刪除主鍵時,都會在表B上加一個全表鎖。這是爲什麼呢?因爲我們沒有給外鍵加索引,在更新或者刪除A表主鍵的時候,需要查看子表B中是否有對應的記錄,以判斷是否可以更新刪除。那如何查找呢?當然只能在子表B中一條一條找了,因爲我們沒有加索引嗎。既然要在子表B中一條一條地找,那就得把整個子表B都鎖定了。由此就會導致以上一系列問題。
    模擬:
    建t_deadlock_p 主表
    在這裏插入圖片描述
    插入對應值
    在這裏插入圖片描述
    建立子表t_d_f 並插入值。
    在這裏插入圖片描述
    1會話執行相關刪除操作,給子表和父表第一行加行級鎖。
    在這裏插入圖片描述
    查看鎖情況,此時沒有鎖。
    在這裏插入圖片描述
    會話2執行另一個刪除操作,子表、父表加行級鎖。
    在這裏插入圖片描述
    由於第一次刪除主表語句時候,觸發了對子表的全表掃描,對子表加了表級鎖,故第二個主表刪除語句出現等待。
    在這裏插入圖片描述
    BLOCK爲1表示阻塞了其它的鎖。
    此時在會話1下刪除id爲2的記錄,2會話報死鎖了。
    在這裏插入圖片描述
    查看阻塞情況
    在這裏插入圖片描述
    trc文件對鎖的類型都交代清楚了。
    在這裏插入圖片描述
    再次模擬,先給外鍵加索引。
    在這裏插入圖片描述
    模擬之前的刪除操作,順利完成。
    在這裏插入圖片描述
    未發現阻塞會話。
    在這裏插入圖片描述
    1.3位圖索引死鎖
    表上的位圖索引遭到併發更新也很容易產生死鎖。在有位圖索引存在的表上面,其實很容易就引發阻塞與死鎖。這個阻塞不是發生在表上面,而是發生在索引上。因爲位圖索引鎖定的範圍遠遠比普通的b-tree索引鎖定的範圍大。
    模擬,先建表並插入數據。
    在這裏插入圖片描述
    在ID列上建bitmap index的話,所有ID=1的會放到一個位圖中,所有ID=2的是另外一個位圖,而在執行DML操作的時候,鎖定的將是整個位圖中的所有行,而不僅僅是DML涉及到的行。由於鎖定的粒度變粗,bitmap index更容易導致死鎖的發生。

    創建位圖索引語句。
    在這裏插入圖片描述
    做更新操作,會話1:所有ID=1的行都被鎖定,會話2:所有ID=2的行都被鎖定在這裏插入圖片描述
    會話1:此時會話被阻塞
    在這裏插入圖片描述
    查看阻塞
    在這裏插入圖片描述
    會話2:會話被阻塞
    在這裏插入圖片描述
    此時的會話層只檢測到鎖等待
    在這裏插入圖片描述
    但alert 檢測到deadlock,這個阻塞不是發生在表上面,而是發生在索引上。
    在這裏插入圖片描述
    死鎖發生的根本原因是對於資源的排他鎖定順序不一致。上面的試驗中,session1對於bitmap index中的2個位圖是先鎖定ID=1的位圖,然後請求ID=2的位圖,而在此之前ID=2的位圖已經被session2鎖定。session2則先鎖定ID=2的位圖,然後請求ID=2的位圖,而此前ID=1的位圖已經被session1鎖定。於是,session1等待session2釋放ID=2的位圖上的鎖,session2等待session1釋放ID=1的位圖上的鎖,死鎖就發生了

而如果我們創建的是普通的B*Tree index,重複上面的試驗則不會出現任何的阻塞和死鎖,這是因爲鎖定的只是DML操作涉及到的行,而不是所有ID相同的行。

1.4常見事務引發的死鎖

如果你有兩個會話,每個會話都持有另一個會話想要的資源,此時就會出現死鎖(deadlock)。例如,如果我的數據庫中有兩個表A和B,每個表中都只有一行,就可以很容易地展示什麼是死鎖。我要做的只是打開兩個會話(例如,兩個SQL*Plus會話)。在會話A中更新表A,並在會話B中更新表B。現在,如果我想在會話B中更新表A,就會阻塞。會話A已經鎖定了這一行。這不是死鎖;只是阻塞而已。因爲會話A還有機會提交或回滾,這樣會話B就能繼續。如果我再回到會話A,試圖更新表B,這就會導致一個死鎖。要在這兩個會話中選擇一個作爲“犧牲品”,讓它的語句回滾。

想要更新表B的會話A還阻塞着,Oracle不會回滾整個事務。只會回滾與死鎖有關的某條語句。會話B仍然鎖定着表B中的行,而會話A還在耐心地等待這一行可用。收到死鎖消息後,會話B必須決定將表B上未執行的工作提交還是回滾,或者繼續走另一條路,以後再提交。一旦這個會話執行提交或回滾,另一個阻塞的會話就會繼續,好像什麼也沒有發生過一樣。

模擬一.兩個表之間不同順序相互更新操作引起的死鎖

模擬二:同一張表刪除和更新之間引起的死鎖

1.5自治事務引發的死鎖
一般來說構成死鎖至少需要兩個會話,而自治事務是一個會話可能引發死鎖。
自治事務死鎖情景:存儲過程INSERT表A,然後INSERT表B;其中INSERT表A觸發TRIGGER T,T也INSERT表B,T是自治事務(AT),AT試圖獲取對B的鎖,結果B已經被主事務所HOLD,這裏會報出來ORA-00060 – 等待資源時檢查到死鎖.

解決方法:去掉了T中的PRAGMA AUTONOMOUS_TRANSACTION聲明,保持和存儲過程事務一致.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章