1. 程式人生 > >MySQL InnoDB儲存引擎:事務實現

MySQL InnoDB儲存引擎:事務實現

事務基礎知識

1、事務ACID特性:

    Atomic(原子性): 事務要麼成功,要麼失敗。

    Consistency(一致性): 事務會把資料庫從一種一致狀態轉換為另一種一致狀態。

     Isolation(隔離性): 事務之間相互隔離,互不影響。

    Durability(永續性): 事務一旦提交,結果是永久性的。

2、資料庫事務的隔離級別有4個。由低到高依次為Read uncommitted、Read committed、Repeatable read、Serializable。

3、併發事務帶來的三個問題。

    (1)髒讀

        事務A讀取L行記錄值為1,未提交。同時,事務B更改了L行記錄為2,且也未提交。事務A再次讀取L行記錄值時,讀取出來的資料為2。則表明產生的“髒讀”,因為事務A讀取了事務B未提交的資料(事務B可能回滾)。

    (2)不可重複讀

        事務A讀取L行記錄值為1,未提交。同時,事務B更改了L行記錄為2,已提交。事務A再次讀取L行記錄值時,讀取出來的資料為2,即同一事務,兩次讀取同一資料的結果不一致,表明產生了“不可重複讀”。

    (3)幻讀

        加入表中只有一行資料,id =1,事務A讀取表中大於1的資料,返回結果集為空,未提交。同時,事務B向表中插入了一條資料,id =2,提交。如果事務A再向表中插入id =2的記錄,此時會報錯,不能插入重複資料。對於事務A來說,明明大於1的記錄為空,但不能插入值為2的資料,表明產生了“幻讀”。

 

MySQL InnoDB儲存引擎中的事務

1、MySQL InnoDB儲存引擎中的鎖。

  InnoDB儲存引擎實現了兩種行級鎖:S Lock(共享鎖) 和X Lock(排他鎖)。如果一個事務對某行記錄加上了共享鎖,那麼其他事務也可以獲得此行記錄上的共享鎖,但是會阻塞排他鎖。

2、一致性非鎖定讀和一致性鎖定讀。

    一致性非鎖定讀:指InnoDB儲存引擎通過多版本控制的方式來獲取當前時間資料庫中的行資料。也就是說如果讀取的行記錄正在被修改,那麼讀取操作不會等待行資料上鎖的釋放,而是讀取行資料的一個快照資料。

在預設設定(Repeatable read)下,InnoDB儲存引擎select * from 語句走的是一致性非鎖定讀。但是並不是每個事物隔離級別下都採用一致性非鎖定讀。哪些隔離級別下不讀快照資料呢?read uncommit和serializable。即時當前事物隔離級別使用一致性非鎖定讀,那麼讀取的快照資料也可能不一樣,因為一個行記錄可能有多個快照版本,由此帶來的併發問題成為 多版本併發控制(Multi Version Concurrency Control,MVCC)。事務隔離級別Read committed下,非鎖定讀總是讀取被鎖定行的最新一份快照資料;而在Repeatable read下,一致性非鎖定讀總是讀取事務開始時的行資料版本。

    一致性鎖定讀:InnoDB對於Select支援兩種一致性鎖定讀。select 。。。for update;select。。。lock in share mode.前者是對行資料加排它鎖,後者是加共享鎖。

3、InnoDB儲存引擎有3種行鎖的演算法。

    Record Lock:單個行記錄上的鎖。

    Gap Lock:間隙鎖,鎖定一個範圍,但不包含記錄本身。

    Next-Key Lock:Gap Lock+Record Lock,鎖定一個範圍,並鎖定記錄本身。

    在Repeatable Read隔離級別下,InnoDB對於行的查詢都是採用Next-Key Lock鎖定演算法。當時如果查詢的索引含有唯一屬性,InnoDB會對Next-Key Lock進行優化,將其降級為Record Lock,即僅鎖定索引本身,而不是範圍。Next-Key Lock演算法正是為了解決“幻讀”問題。

    Record Lock 在鎖定時,總是會鎖住索引記錄。

    可以通過設定隔離級別為Read Commited和配置引數來關閉gap Lock,此時除了外來鍵約束和唯一性檢查依然需要Gap Lock外,其他僅使用Record Lock進行鎖定。

4、MySQL InnoDB儲存引擎中的事務

   InnoDB儲存引擎中,事務的隔離性是通過鎖來實現的。redo Log(重做日誌)用來保證事務的原子性和永續性,事務的一致性是通過undo log來實現。redo log恢復提交事務修改的頁操作,undo log回滾行記錄到某個特定版本。

5、redo log 重做日誌包括兩部分:1 是記憶體中的重做日誌緩衝 ;2 是重做日誌檔案。在事務提交時,必須先將該事務的所有日誌寫入到重做日誌檔案進行持久化,待事務commit操作完成才算完成。

     在每次事務提交之前,將重做日誌寫入緩衝,為了持久化重做日誌,儲存引擎需要呼叫一次fsync操作,同步緩衝到重做日誌檔案中。允許設定重做日誌緩衝的重新整理為定時重新整理,而不是每一次事務提交都重新整理到檔案中,來提高資料庫效能。 

6、undo log 。當用戶執行的事務失敗了,需要請求回滾時,就可以利用undo log來講資料回滾到修改之前。undo log是存放在資料庫內部的一個特殊段(segemnt)。undo 除了回滾使用外,MVCC的實現也是通過undo來完成,用讀取一行記錄時,如果該記錄已經被鎖,則當前事務可以通過undo讀取之前的行版本資訊,來實現非鎖定讀。undo log也會產生redo log。

    undo log所在的頁在事務提交後,可以重用。但事務提交後並不能馬上刪除undo log及 undo log所在的頁,可能有其他事務通過undo log來得到行記錄之前的版本。是否能刪除,是由purge執行緒來判斷。

 

參考:

《MySQL技術內幕:InnoDB儲存引擎》