spring學習筆記(20)資料庫事務併發與鎖詳解

weixin_33766168發表於2016-03-10

多事務執行併發問題

在實際應用中,往往是一臺(或多臺)伺服器向無數客戶程式提供服務,當伺服器查詢資料庫獲取資料時,如果沒有采用必要的隔離機制,可能會存在資料庫事務的併發問題,下面是一些常見的併發問題分類:

1. 第一類丟失更新:撤銷一個事務,其他事務已提交的更新資料覆蓋
2. 第二類丟失更新:一個事務覆蓋另一個事務已提交的更新資料
3. 髒讀:一個事務讀到另一個事務未提交的資料
4. 虛讀:一個事物讀到另一個已提交的新插入資料 
5. 不可重複讀:事務讀到另一個事務已提交的更新資料

下面對這幾類併發問題進行詳細介紹:

1. 第一類丟失更新

產生過程:兩個事務更新同一資料,第一個事務被提交,第一個事務被撤銷,會把第一個事務所做的更新也撤銷,示意圖如下所示:
這裡寫圖片描述

2. 第二類丟失更新

產生過程:兩個事務各自基於最初的查詢結果提交資料,例項流程如下圖所示:
這裡寫圖片描述

3. 髒讀

產生過程:事務二查詢到事務一未提交資料,事務二根據此資料進行操作,事務一緊接著撤銷資料,導致事務二操縱的是“髒資料”,例項流程如下圖所示:
這裡寫圖片描述

4.虛讀(幻象讀)

產生過程:對某行執行插入或刪除操作,而該行屬於某個事務正在讀取的行的範圍。若對資料精度要求不高,則影響不大,例項流程如下圖所示:
這裡寫圖片描述

5.不可重複讀

產生過程:一個事務查詢到另一事務已提交的對資料的更新,例項流程如下圖所示:
這裡寫圖片描述
與髒讀區別:髒讀->讀取前一事務未提交的髒資料,不可重複讀->重新讀取了前一事務已提交的資料

資料庫系統鎖的基本原理

1. 鎖的多粒度及自動升級:

  1. 鎖的多粒度按型別可分成下面幾類:
    • 資料庫級鎖
    • 表級鎖
    • 區域級鎖
    • 頁面級鎖
    • 鍵值級鎖:鎖定資料庫表中帶有索引的一行資料
    • 行級鎖
  2. 對資料的封鎖力度越大,往往隔離性越高,但併發效能變差。
  3. 對資料施行的鎖粒度越高,併發性往往越大,但這意味著在大併發量時鎖的數量的急劇增多,由此會帶來系統資源的嚴重負載,影響系統系統。常用的資料庫都有事務鎖自動升級功能,當系統效能因為鎖數量過大而急劇變差時,往往會升級使用更粗粒度的鎖來擴大封鎖面,減少鎖數優化系統資源。

2. 鎖的型別和相容性:

  1. 共享鎖

    • 加鎖條件:讀取資料
    • 解鎖條件:讀取完畢
    • 相容性:放置了共享鎖的資源,能再放置共享鎖和獨佔鎖
    • 併發性:多事務訪問相同資料,多鎖同時讀
  2. 獨佔鎖(排它鎖)

    • 加鎖條件:修改資料且無其他鎖存在
    • 解鎖條件:事務結束
    • 相容性:不與其他鎖相容
  3. 更新鎖

    • 加鎖條件:update操作
    • 加鎖更新步驟:
      1. 獲得一個共享鎖,讀資料
      2. 升級為獨佔鎖,更新資料
    • 相容性:與共享鎖相容,同一資源最多一把更新鎖,能有效避免死鎖產生,我們知道,共享鎖的相容性是最好的,加入一個資料同時被兩把共享鎖鎖住,如果這時兩條執行緒併發修改資料,由於共享鎖的非排他性,可能會同時出現兩把獨佔鎖鎖住資料,這樣就會產生死鎖了,而更新鎖排斥獨佔鎖,當出現更新操作時,只能將更新鎖本身升級為獨佔鎖,而有效避免死鎖產生。
    • 併發性:效能一般,多事務訪問,單事務修改。
      -

3. 死鎖產生及其解決方法:

  1. 產生過程:多事務鎖定一個資源->試圖去鎖定對方已鎖定的資源->多事務處於等待對方釋放鎖資源狀態,示意圖如下所示:
    這裡寫圖片描述
  2. 防止方法
    1. 合理安排表訪問順序
    2. 對事務要求不高,允許髒讀(不加鎖)
    3. 錯開多事務訪問相同資源的時間
    4. 使用盡可能低的事務隔離級別
    5. 使用短事務(操作儘可能少,時間儘可能短)
    6. 將大事務分解成多個小事務順序執行

4. 悲觀鎖與悲觀鎖

  1. 悲觀鎖:顯式為資料加鎖,常見有如下兩種加鎖方式
    1. 顯式指定獨佔鎖:select … for update
    2. 在資料庫增加表明狀態的LOCK欄位
  2. 樂觀鎖:通過版本控制實現,示意圖如下所示:
    這裡寫圖片描述
    通過樂觀鎖的版本控制,我們能夠更好地提高併發事務的效能。

3. 資料庫的事務隔離級別

4種隔離級別從高到低依次為:
- Serializable:序列化
- Repeatable Read: 可重複讀
- Read Commited:讀已提交的資料
- Read UnCommited:讀未提交的資料

它們對併發事務問題的支援如下圖所示
這裡寫圖片描述

4. spring的事務傳播行為

事務傳播行為型別 說明
PROPAGATION_REQUIRED 如果當前沒有事務,就新建一個,如果已經存在,則加入到事務中這是最常見的選擇。
PROPAGATION_SUPPORTS 表示事務對當前方法可有可無,如果有,則按該事務執行,如果當前沒有事務,就以非事務方式執行。
PROPAGATION_MANDATORY 表示當前方法必須在一個事務中執行,而且如果當前沒有事務,就丟擲異常。
PROPAGATION_REQUIRES_NEW 表示當前方法總是需要獨立的新事務,如果當前已存在事務,就會把當前事務掛起,直到新的事務提交或者回滾才恢復執行
PROPAGATION_NOT_SUPPORTED 表示當前方法不需要事務,如果當前存在事務,就把當前事務掛起。
PROPAGATION_NEVER 表示當前方法不需要事務,而且如果當前存在事務,則丟擲異常。
PROPAGATION_NESTED 如果當前存在事務,則在巢狀事務內執行,如果巢狀事務存在,並且外層事務丟擲異常回滾,那麼內層事務必須回滾,反之,內層事務並不影響外層事務

相關文章