1. 程式人生 > >資料庫的事務隔離技術 之 MVCC

資料庫的事務隔離技術 之 MVCC

在mysql中,提供了兩種事務隔離技術,第一個是mvcc,第二個是next-key技術。

這個在使用不同的語句的時候可以動態選擇。不加lock in share mode之類的就使用mvcc。否則使用next-key。

mvcc的優勢是不加鎖,併發性高。缺點是不是實時資料。next-key的優勢是獲取實時資料,但是需要加鎖。

同時需要注意幾點:

1.事務的快照時間點是以第一個select來確認的。所以即便事務先開始。但是select在後面的事務的update之類的語句後進行,那麼它是可以獲取後面的事務的對應的資料。

2.mysql中資料的存放還是會通過版本記錄一系列的歷史資料,這樣,可以根據版本查詢資料。


 本片博文先講解MVCC技術,下一篇博文講解next-key技術


 

多版本併發控制(Multi-Version Concurrency Control, MVCC)是 MySQL 的 InnoDB 儲存引擎實現隔離級別的一種具體方式,用於實現提交讀和可重複讀這兩種隔離級別。而未提交讀隔離級別總是讀取最新的資料行,無需使用 MVCC。可序列化隔離級別需要對所有讀取的行都加鎖,單純使用 MVCC 無法實現。

版本號

  • 系統版本號:是一個遞增的數字,每開始一個新的事務,系統版本號就會自動遞增。
  • 事務版本號:事務開始時的系統版本號。

隱藏的列

MVCC 在每行記錄後面都儲存著兩個隱藏的列,用來儲存兩個版本號:

  • 建立版本號:指示建立一個數據行的快照時的系統版本號;
  • 刪除版本號:如果該快照的刪除版本號大於當前事務版本號表示該快照有效,否則表示該快照已經被刪除了。

Undo 日誌

MVCC 使用到的快照儲存在 Undo 日誌中,該日誌通過回滾指標把一個數據行(Record)的所有快照連線起來。

 

實現過程

以下實現過程針對可重複讀隔離級別。

當開始新一個事務時,該事務的版本號肯定會大於當前所有資料行快照的建立版本號,理解這一點很關鍵。

1. SELECT

多個事務必須讀取到同一個資料行的快照,並且這個快照是距離現在最近的一個有效快照。但是也有例外,如果有一個事務正在修改該資料行,那麼它可以讀取事務本身所做的修改,而不用和其它事務的讀取結果一致。

把沒有對一個數據行做修改的事務稱為 T,T 所要讀取的資料行快照的建立版本號必須小於 T 的版本號,因為如果大於或者等於 T 的版本號,那麼表示該資料行快照是其它事務的最新修改,因此不能去讀取它。除此之外,T 所要讀取的資料行快照的刪除版本號必須大於 T 的版本號,因為如果小於等於 T 的版本號,那麼表示該資料行快照是已經被刪除的,不應該去讀取它。

2. INSERT

將當前系統版本號作為資料行快照的建立版本號。

3. DELETE

將當前系統版本號作為資料行快照的刪除版本號。

4. UPDATE

將當前系統版本號作為更新前的資料行快照的刪除版本號,並將當前系統版本號作為更新後的資料行快照的建立版本號。可以理解為先執行 DELETE 後執行 INSERT。


 

快照讀與當前讀

1. 快照讀

使用 MVCC 讀取的是快照中的資料,這樣可以減少加鎖所帶來的開銷。

select * from table ...;

2. 當前讀

讀取的是最新的資料,需要加鎖。以下第一個語句需要加 S 鎖,其它都需要加 X 鎖。

select * from table where ? lock in share mode;
select * from table where ? for update;
insert;
update;
delete;

 

快照讀

  讀取的是記錄資料的可見版本(可能是過期的資料),不用加鎖

當前讀

  讀取的是記錄資料的最新版本,並且當前讀返回的記錄都會加上鎖,保證其他事務不會再併發的修改這條記錄
  概念說的比較虛,也不好理解,接著舉一個例子吧,假設你開啟了兩個事務,分別是A和B,這裡有個張表,user表,裡面有四條資料

 

1、insert 快照讀(照片)

  當你執行select *之後,在A與B事務中都會返回4條一樣的資料,這是不用想的,當執行select的時候,innodb預設會執行快照讀,相當於就是給你目前的狀態拍了一張照片,以後執行select 的時候就會返回當前照片裡面的資料,當其他事務提交了也對你不造成影響,和你沒關係,這就實現了可重複讀了,那這個照片是什麼時候生成的呢?不是開啟事務的時候,是當你第一次執行select的時候,也就是說,當A開啟了事務,然後沒有執行任何操作,這時候B insert了一條資料然後commit,這時候A執行 select,那麼返回的資料中就會有B新增的那條資料......之後無論再有其他事務commit都沒有關係,因為照片已經生成了,而且不會再生成了,以後都會參考這張照片。(這就是為什麼資料可能是過期資料的原因)

2、update、insert、delete 當前讀

  當你執行這幾個操作的時候預設會執行快照讀,也就是會讀取最新的記錄,也就是別的事務提交的資料你也可以看到,這樣很好理解啊,假設你要update一個記錄,另一個事務已經delete這條資料並且commit了,這樣不是會產生衝突嗎,所以你update的時候肯定要知道最新的資訊啊。

  我在這裡介紹一下update的過程吧,首先會執行當前讀,然後把返回的資料加鎖,之後執行update,然後把鎖釋放掉。加鎖是防止別的事務在這個時候對這條記錄做什麼,預設加的是排他鎖,也就是你讀都不可以,這樣就可以保證資料不會出錯了。