數據庫中死鎖那些事兒

說起數據中的死鎖,已經多次在筆試題目中遇到。今天特此做一個數據庫死鎖方面的總結,以絕後患,吼吼!

一、首先我們來看幾個定義:


1.死鎖

所謂死鎖: 是指兩個或兩個以上的進程在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等待的進程稱爲死鎖進程。 由於資源佔用是互斥的,當某個進程提出申請資源後,使得有關進程在無外力協助下,永遠分配不到必需的資源而無法繼續運行,這就產生了一種特殊現象死鎖。

2.數據庫

數據庫(Database)是按照數據結構來組織、存儲和管理數據的倉庫。

3.產生死鎖的必要條件

  •  互斥條件:指進程對所分配到的資源進行排它性使用,即在一段時間內某資源只由一個進程佔用。如果此時還有其它進程請求資源,則請求者只能等待,直至佔有資源的進程用畢釋放。
  • 請求和保持條件:指進程已經保持至少一個資源,但又提出了新的資源請求,而該資源已被其它進程佔有,此時請求進程阻塞,但又對自己獲得的其它資源保持不放。
  • 不剝奪條件:指進程已獲得的資源,在未使用完之前,不能被剝奪,只能在使用完時由自己釋放。
  • 環路等待條件:指在發生死鎖時,必然存在一個進程——資源的環形鏈,即進程集合{P0,P1,P2,···,Pn}中的P0正在等待一個P1佔用的資源;P1正在等待P2佔用的資源,……,Pn正在等待已被P0佔用的資源。

4.處理死鎖的基本方式

      1) 預防死鎖。
  這是一種較簡單和直觀的事先預防的方法。方法是通過設置某些限制條件,去破壞產生死鎖的四個必要條件中的一個或者幾個,來預防發生死鎖。預防死鎖是一種較易實現的方法,已被廣泛使用。但是由於所施加的限制條件往往太嚴格,可能會導致系統資源利用率和系統吞吐量降低。
  2) 避免死鎖。
  該方法同樣是屬於事先預防的策略,但它並不須事先採取各種限制措施去破壞產生死鎖的的四個必要條件,而是在資源的動態分配過程中,用某種方法去防止系統進入不安全狀態,從而避免發生死鎖。
  3)檢測死鎖。
  這種方法並不須事先採取任何限制性措施,也不必檢查系統是否已經進入不安全區,此方法允許系統在運行過程中發生死鎖。但可通過系統所設置的檢測機構,及時地檢測出死鎖的發生,並精確地確定與死鎖有關的進程和資源,然後採取適當措施,從系統中將已發生的死鎖清除掉。
  4)解除死鎖。
  這是與檢測死鎖相配套的一種措施。當檢測到系統中已發生死鎖時,須將進程從死鎖狀態中解脫出來。常用的實施方法是撤銷或掛起一些進程,以便回收一些資源,再將這些資源分配給已處於阻塞狀態的進程,使之轉爲就緒狀態,以繼續運行。死鎖的檢測和解除措施,有可能使系統獲得較好的資源利用率和吞吐量,但在實現上難度也最大。

二、數據庫中的死鎖是什麼樣的!


1.SQL server鎖的機制

SQL server的所有活動都會產生鎖。鎖定的單元越小,就越能越能提高併發處理能力,但是管理鎖的開銷越大。如何找到平衡點,使併發性和性能都可接受是SQL Server的難點。
SQL Server有如下幾種瑣:
1、 共享鎖
用於只讀操作(SELECT),鎖定共享的資源。共享鎖不會阻止其他用戶讀,但是阻止其他的用戶寫和修改。
2、 更新鎖
更新鎖是一種意圖鎖,當一個事物已經請求共享瑣後並試圖請求一個獨佔鎖的時候發生更新瑣。例如當兩個事物在幾行數據行上都使用了共享鎖,並同時試圖獲取獨佔鎖以執行更新操作時,就發生了死鎖:都在等待對方釋放共享鎖而實現獨佔鎖。更新鎖的目的是隻讓一個事物獲得更新鎖,防止這種情況的發生。
3、 獨佔鎖(排它鎖)
一次只能有一個獨佔鎖用在一個資源上,並且阻止其他所有的鎖包括共享縮。寫是獨佔鎖,可以有效的防止’髒讀’
4、 意圖鎖
在使用共享鎖和獨佔鎖之前,使用意圖鎖。從表的層次上查看意圖鎖,以判斷事物能否獲得共享鎖和獨佔鎖,提高了系統的性能,不需從爺或者行上檢查。
5、 計劃鎖
Sch-M,Sch-S。對數據庫結構改變時用Sch-M,對查詢進行編譯時用Sch-S。這兩種鎖不會阻塞任何事物鎖,包括獨佔鎖。

讀是共享鎖,寫是排他鎖,先讀後更新的操作是更新鎖,更新鎖成功並且改變了數據時更新鎖升級到排他鎖。

2.下面我們看下如何避免死鎖


1 使用事務時,儘量縮短事務的邏輯處理過程,及早提交或回滾事務;
2 設置死鎖超時參數爲合理範圍,如:3分鐘-10分種;超過時間,自動放棄本次操作,避免進程懸掛;
3 所有的SP都要有錯誤處理(通過@error
4 一般不要修改SQL SERVER事務的默認級別。不推薦強行加鎖
5 優化程序,檢查並避免死鎖現象出現;
1)合理安排表訪問順序
2)在事務中儘量避免用戶干預,儘量使一個事務處理的任務少些。
3)採用髒讀技術。髒讀由於不對被訪問的表加鎖,而避免了鎖衝突。在客戶機/服務器應用環境中,有些事務往往不允許讀髒數據,但在特定的條件下,我們可以用髒讀。
4)數據訪問時域離散法。數據訪問時域離散法是指在客戶機/服務器結構中,採取各種控制手段控制對數據庫或數據庫中的對象訪問時間段。主要通過以下方式實現: 合理安排後臺事務的執行時間,採用工作流對後臺事務進行統一管理。工作流在管理任務時,一方面限制同一類任務的線程數(往往限制爲1個),防止資源過多佔用; 另一方面合理安排不同任務執行時序、時間,儘量避免多個後臺任務同時執行,另外,避免在前臺交易高峯時間運行後臺任務
5)數據存儲空間離散法。數據存儲空間離散法是指採取各種手段,將邏輯上在一個表中的數據分散到若干離散的空間上去,以便改善對錶的訪問性能。主要通過以下方法實現: 第一,將大表按行或列分解爲若干小表; 第二,按不同的用戶羣分解。
6)使用儘可能低的隔離性級別。隔離性級別是指爲保證數據庫數據的完整性和一致性而使多用戶事務隔離的程度,SQL92定義了4種隔離性級別:未提交讀、提交讀、可重複讀和可串行。如果選擇過高的隔離性級別,如可串行,雖然系統可以因實現更好隔離性而更大程度上保證數據的完整性和一致性,但各事務間衝突而死鎖的機會大大增加,大大影響了系統性能。
7)使用Bound Connections。Bound connections 允許兩個或多個事務連接共享事務和鎖,而且任何一個事務連接要申請鎖如同另外一個事務要申請鎖一樣,因此可以允許這些事務共享數據而不會有加鎖的衝突。
8)考慮使用樂觀鎖定或使事務首先獲得一個獨佔鎖定。 


大家看下下面的情況是否會出現死鎖呢?

A. select , update,select
B.select,select,update
C.select,update,update
D.update,select,update
上面這四種情況哪種會出現死鎖,哪種出現死鎖呢?你的理由又是什麼呢?

3.下面我們來看下下面的這個死鎖問題!

-- A事務先更新table1表,然後延時30秒,再更新table2表;
begin tran
update table1 set A='aa' where B='b2';
--這將在 Table1 中生成排他行鎖,直到事務完成後纔會釋放該鎖。
waitfor delay '00:00:30';
--進入延時
update table2 set D='d5' where E='e1' ;
commit tran
-- B事務先更新table2表,然後延時10秒,再更新table1表;
begin tran
update table2 set D='d5' where E='e1';
--這將在 Table2 中生成排他行鎖,直到事務完成後纔會釋放該鎖
waitfor delay '00:00:10'
--進入延時
update table1 set A='aa' where B='b2' ;
commit tran

A事務先更新table1表,然後延時30秒,再更新table2表;begin tranupdate table1 set A='aa' where B='b2';--這將在 Table1 中生成排他行鎖,直到事務完成後纔會釋放該鎖。waitfor delay '00:00:30';--進入延時update table2 set D='d5' where E='e1' ;commit tran-- B事務先更新table2表,然後延時10秒,再更新table1表;begin tranupdate table2 set D='d5' where E='e1';--這將在 Table2 中生成排他行鎖,直到事務完成後纔會釋放該鎖waitfor delay '00:00:10'--進入延時update table1 set A='aa' where B='b2' ;commit tran
若併發執行上述兩個事務,A,B兩事務都要等待對方釋放排他鎖,這樣便形成了死鎖。




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