MySQL 筆記 - 事務&鎖

xiaoyusilen發表於2018-08-17

寫在前面

這是一篇讀(重)書(點)筆(摘)記(要)~內容為《高效能 MySQL》第一章~

and 七夕快樂,所以今天的配圖是粉紅色的(๑•̀ㅂ•́)و✧

事務

簡單的說,事務就是一組原子性的 SQL 查詢,這一組 SQL 要麼全部執行成功,要麼全部執行失敗。這裡簡單介紹一下事務的 ACID,ACID 表示原子性、一致性、隔離性和永續性。

  • 原子性:一個事務是不可分割的最小工作單元,整個事務要麼全部成功,要麼全部失敗,不可能只執行中間的一部分操作。
  • 一致性:執行事務是使得資料庫從一個一致性狀態到另一個一致性狀態,如果事務最終沒有被提交,那麼事務所做的修改也不會儲存到資料庫中。
  • 隔離性:通常來說,一個事務提交之前對其他事務是不可見的,但是這裡所說的不可見需要考慮隔離級別,比如未提交讀在提交前對於其他事務來說也是可見的,隔離級別,在下面會詳細講。
  • 永續性:事務一旦被提交,那麼對資料庫的修改會被永久的儲存,即使資料庫崩潰修改後的資料也不會丟失。

隔離級別

SQL 標準中定義了四種隔離級別,這裡簡單介紹一下這四種隔離級別。

  • 未提交讀:未提交讀的意思是,事務中的修改,即使沒有提交,對其他事務也都是可見的,但是這樣會出現髒讀,一般情況下,通常都不會使用未提交讀。
  • 提交讀:提交讀的意思是,一個事務所做的修改在提交之前對其他事務都是不可見的,這個級別也叫做“不可重複讀”,因為執行兩次相同的操作,可能會得到不同的結果。
  • 可重複讀:可重複讀解決了髒讀的問題,這個級別保證了同一個事務多次讀取同樣記錄的結果是一致的,但是這個隔離級別無法解決幻讀的問題,所謂幻讀就是說,當某個事務讀取範圍資料時,另一個事務又在該範圍內插入了新的記錄,當之前的事務再次讀取該範圍資料時,會產生幻行。InnoDB 儲存引擎通過 MVCC 解決了幻讀的問題,可重複讀是 MySQL 預設的事務隔離級別。
  • 可序列化:是最高的隔離級別,避免了前面說到的幻讀問題。可序列化會給讀取的每一行都加鎖,所以可能導致大量超時和鎖爭用的問題,實際中很少使用這個隔離級別。

死鎖

死鎖是指兩個或者多個事務在同一資源上相互佔用,並請求鎖定對方佔用的資源。解決死鎖的方法就是回滾一個或者多個事務。

MVCC

MVCC 可以看做是行鎖的一個變種,在很多情況下 MVCC 可以避免加鎖,因此開銷更小,不同事務型儲存引擎對於 MVCC 的實現各有不同。 MVCC 的實現是通過儲存資料在某個時間點的快照來實現的。也就是說,不管執行多長時間,每個事務看到的資料都是一致的。根據事務的開始時間不同,每個事務對同一張表,同一時刻看到的資料可能是不一樣的。這裡簡單介紹一下 InnoDB 的 MVCC。 InnoDB 的 MVCC 通過在每行記錄後面儲存兩個隱藏的列來實現。這兩個列,一個儲存了行的建立時間,一個儲存了行的過期時間,儲存的不是實際的時間,而是版本號。每開始一個新的事務,系統版本號都會自動遞增。事務開始時刻的系統版本號會作為事務的版本號,用來和查詢到的每行記錄的版本號作對比。下面詳細介紹一下在可重複讀隔離級別下,MVCC 的具體操作。

  • SELECT
    • InnoDB 會根據以下兩個條件檢查每條記錄:
      • 只查詢版本小於等於事務版本號的行
      • 只查詢未定義刪除時間或者刪除時間大於事務版本號的行
  • INSERT
    • InnoDB 為新插入的每一行儲存當前的系統版本號作為行版本號
  • DELETE
    • InnoDB 為刪除的每一行儲存當前的系統版本號作為行的刪除版本號
  • UPDATE
    • InnoDB 新增一條記錄,儲存當前系統版本號作為新增行的版本號
    • 在被刪除記錄的原始行,儲存當前系統版本號作為被刪除記錄行的刪除版本號

優點:

  1. 因為有了兩個隱藏列來記錄資料的狀態,所以大多數讀操作都可以不加鎖
  2. 效能好,同時可以保證讀取的資料是正確的

缺點:

  1. 需要額外的空間記錄每行的狀態
  2. 需要行狀態的維護和檢查

如何解決幻讀

MVCC 解決幻讀的時候使用了間隙鎖,也就是 next-key lock,這部分就要先從 InnoDB 的三種行鎖說起:

  • Record Lock:單個行記錄上的鎖,鎖住的是索引
  • Gap Lock:區間鎖,鎖定一個區間範圍,但不包括記錄本身,開區間
  • Next-Key Lock:間隙鎖,Record Lock + Gap Lock

舉個簡單的例子,

select id from user where id > 15 and id < 30
複製程式碼

Next-Key Lock

圖示清楚的表示了間隙鎖~

總結

這一章發的貌似有點晚了,應該在索引之前發的。But,依然感謝觀看~ 最後表白我潘,mua! (*╯3╰),七夕快樂~

Reference

《高效能 MySQL》

相關文章