背景:
曾經的一位同事問我:"數據庫只有並發INSERT 操作,會造成死鎖么?",我沒有太多思考地回答"不會",但真的不會嗎?
測試:
--================================= --創建測試表 CREATE TABLE TB3 ( ID INT PRIMARY KEY ) GO --=================================== --新開回話1 BEGIN TRAN INSERT INTO TB3 SELECT 2 WAITFOR DELAY '0:0:10' INSERT INTO TB3 SELECT 1 --=================================== --新開回話2 BEGIN TRAN INSERT INTO TB3 SELECT 1 WAITFOR DELAY '0:0:10' INSERT INTO TB3 SELECT 2
在上面的兩個回話中,由於主鍵(唯一約束)的限制,相同的key對應相同的lock Resource,導致需要等待對方所獲取的lock Resource,從而引發死鎖
而如果將主鍵修改為非唯一索引,則不會引發死鎖,相同的key對應不相同的lock Resource,因此不會造成相互等待也不引發死鎖。
--====================================================================
--華麗的PS
對於最常見的死鎖場景:
事務1 獲取表TB1上的資源,請求表TB2上的資源
事務2 獲取表TB2上的資源,請求表TB1上的資源
很多開發人員都會有意識保證各個事務訪問不同表的順序,從而避免此類死鎖的發生,但很少會考慮對相同表的訪問順序,尤其在輸入值被參數化的情況,如在下面的情況下:
BEGIN TRAN UPDATE TB1 SET C2=@P2 WHERE C1=@P1 UPDATE TB1 SET C2=@P3 WHERE C1=@P3
COMMIT
在考慮是否會引發死鎖時,我們除了分析當前語句外,還得檢查這些語句所涉及到的表相關對象:觸發器+外鍵+索引,還需分析其他業務場景的潛在影響。
PS:很多我們自認為正確的小結論,洗洗(細細)分析下,根本就是錯誤,而這些西奧結論,可能造成很惡劣影響。
--========================================================
照例妹子鎮貼

圖片來源於一豆瓣友鄰
