一、死結的四個必要條件
1、互斥條件(Mutual exclusion):資源不能被共用,只能由一個進程使用。
2、請求與保持條件(Hold and wait):已經得到資源的進程可以再次申請新的資源。
3、非剝奪條件(No pre-emption):已經分配的資源不能從相應的進程中被強制地剝奪。
4、迴圈等待條件(Circular wait):系統中若干進程組成環路,該環路中每個進程都在等待相鄰進程正佔用的資源。
二、 避免死結
1、按同一順序訪問對象
如果所有並發事務按同一順序訪問對象,則發生死結的可能性會降低。例如,如果兩個並發事務獲得 Supplier 表上的鎖,然後獲得 Part 表上的鎖,則在其中一個事務完成之前,另一個事務被阻塞在 Supplier 表上。第一個事務提交或復原後,第二個事務繼續進行。不發生死結。將預存程序用於所有的資料修改可以標準化訪問對象的順序。
2、避免事務中的使用者互動
避免編寫包含使用者互動的事務,因為運行沒有使用者互動的批處理的速度要遠遠快於使用者手動響應查詢的速度,例如回覆應用程式請求參數的提示。例如,如果事務正在等待使用者輸入,而使用者去吃午餐了或者甚至回家過周末了,則使用者將此事務掛起使之不能完成。這樣將降低系統的輸送量,因為事務持有的任何鎖只有在事務提交或復原時才會釋放。即使不出現死結的情況,訪問同一資源的其它事務也會被阻塞,等待該事務完成。
3、保持事務簡短並在一個批處理中
在同一資料庫中並發執行多個需要長時間啟動並執行事務時通常發生死結。事務已耗用時間越長,其持有排它鎖或更新鎖定的時間也就越長,從而堵塞了其它活動並可能導致死結。
保持事務在一個批處理中,可以最小化事務的網路通訊往返量,減少完成事務可能的延遲並釋放鎖。
4、使用低隔離等級
確定事務是否能在更低的隔離等級上運行。執行提交讀允許事務讀取另一個事務已讀取(未修改)的資料,而不必等待第一個事務完成。使用較低的隔離等級(例如提交讀)而不使用較高的隔離等級(例如可串列讀)可以縮短持有共用鎖定的時間,從而降低了鎖定爭奪。
5、使用綁定串連
使用綁定串連使同一應用程式所開啟的兩個或多個串連可以相互合作。次級串連所獲得的任何鎖可以象由主串連獲得的鎖那樣持有,反之亦然,因此不會相互阻塞
6、SELECT語句加With(NoLock)提示
預設情況下SELECT語句會對查詢到的資源加S鎖(共用鎖定),S鎖與X鎖(獨佔鎖定)不相容;但加上With(NoLock)後,SELECT不對查詢到的資源加鎖(或者加Sch-S鎖,Sch-S鎖可以與任何鎖相容);從而可以是這兩條SQL可以並發地訪問同一資源。當然,此方法適合解決讀與寫並發死結的情況,但加With(NoLock)可能會導致髒讀。