事務的併發控制有三種方案:悲觀鎖,樂觀鎖以及多版本併發控制。多版本併發控制能夠與前面兩種結合,從而提升數據庫的讀性能。mysql
前面二者都是經過延遲或者終止相應的事務來解決事務之間的競爭條件來保證事務的串行執行。可是在實際場景中,事務大多數都是隻讀的,讀請求是寫請求的不少倍。若是讀寫之間沒有併發控制機制,最壞的狀況就是讀請求和讀到了已經寫入的數據,這對不少應用是能夠接受的。sql
MVCC的全稱就是多版本併發控制。它保存了已經更改的舊版本信息,以支持併發和回滾等事務功能。這項技術使得InnoDB的事務隔離級別下執行一致性讀操做有了保證。換言之,爲了查詢在一些正在被另一個事務更新的行,而且能夠看到它們被更新以前的值。這是一個能夠用來加強併發性的強大技術,由於這樣一來的話查詢就不用等待另外一個事務釋放鎖。這項技術在數據庫領域並非廣泛使用的。數據庫
每一次寫操做都會建立一個新版本的數據,每個版本的數據行都有一個惟一的時間戳。讀操做會從有限個多版本的記錄中找到最合適的結果直接返回,就是時間戳的最大值。更新操做就有些複雜了, 事務會先讀取最新版本的數據計算出更新後的結果,而後建立一個新版本的數據,新數據的時間戳是目前數據行最大版本+1。數據版本的刪除也是根據時間戳來選擇的。MySql會將版本最低的數據定時刪除以保證不會出現大量的歷史記錄。 這時候讀寫操做之間的衝突就不須要被關注。 併發
MVVC最大的好處是:讀不加鎖,讀寫不衝突。在讀多寫少的應用中,讀寫不衝突很是重要,極大的增長了系統的併發性。利用MVCC實現了一致性非鎖定讀,保證了在同一個事務中屢次讀取相同的數據返回的結果是同樣的,解決了不可重複讀問題。性能
因此在mysql的repeatable read級別下也不會出現不可能重複讀問題,而且經過Next-Key Lock解決了幻讀問題。 事務
InnoDB使用的是行鎖,而且採用了多版本併發控制來提升讀操做的性能。table
什麼是多版本併發控制呢?date
其實就是在每一行記錄的後面增長了三個隱藏列,記錄建立版本號和刪除版本號。而每個事務開啓的時候,都會有惟一的遞增版本號,被操做的數據會生成一條新的數據行(臨時),可是在提交前對其餘事務是不可見的,對於數據的更新(包括增刪改)操做成功,會將這個版本號更新到數據的行中,事務提交成功,將新的版本號更新到此數據行中。這樣保證了每一個事務操做的數據,都是互不影響,也不存在鎖的問題。select
MVVC下的CRUD請求
select
當隔離級別是REPEATABLE READ時select操做,InnoDB必須每行數據來保證它符合兩個條件:
1.InnoDB必須找到一個行的版本,它至少要和事務的版本同樣老(也即他的版本號不大於事務的版本號)。這保證了無論是事務開始以前,或者事務建立時,或者修改了這行數據的時候,這行數據是存在的。
2.這行數據的刪除版本必須是未定義或者比事務版本大。這樣能夠保證在事務開始以前這行數據沒有被刪除。
insert
InnoDB爲這個新行記錄當前的系統版本號。
delete
InnoDB將當前的系統版本號更新到這一行的刪除id
update
InnoDB會寫一個這行數據的新拷貝,這個拷貝的版本爲當前的系統版本號。同時也會將這個版本號寫到舊行的刪除版本號裏。
這種額外的記錄所帶來的結果就是對於大多數查詢而言根本不須要得到一個鎖。他們只是簡單的以最快的速度讀取數據,確保只選擇符合條件的行。這個方案的缺點在於存儲引擎必須爲每一行存儲更多的數據,作更多的檢查工做,處理更多善後操做。
MVVC只工做在REPEATABLE READ和READ COMMITED隔離級別下。READ UNCOMMITED不是MVVC兼容的,由於查詢不能找到適合他們事務版本的行版本,它們每次只能讀到最新的版本。Serablable也不與MVVC兼容,由於讀操做會鎖定他們返回的每一行數據。