咱們知道事務的隔離級別中只有:可串行化 能夠解決幻讀的問題,但串行化會在讀取的每一行數據上都加鎖,這可能會致使大量的超時和鎖爭用的問題,鎖開銷很是之大,在實際的項目應用中,只有在必須確保數據的一致性且沒有併發的狀況下才會考慮使用,通常這一隔離級別不多會被用到。而在MySQL的事務型存儲引擎中,默認隔離級別是 可重複讀,但可重複讀並不能解決幻讀的問題,所以,MySQL便引入的MCVV(多版本控制, 將歷史數據存一份快照,因此其餘事務增長與刪除數據,對於當前事務來講是不可見的。 )來解決幻讀的問題,並使大多數的讀操做均可以不用加鎖。併發
MVCC能夠當作是行鎖的變種,但它的開銷更低,這得益於它的實現機制,使它能在不少狀況下避免加鎖操做,例如非阻塞的讀操做。MVCC經過保存數據在某個時間點的快照來實現,根據每一個事務的開始時間不一樣,每一個事務對同一張表,同一時刻看到的數據都是不同的,而每一個事務在他們各自的事務內的數據又是保持一致。spa
以MySQL中的InnoDB爲例,其MVCC實現是經過在每行記錄後面保存兩個隱藏的列,而這兩個列分別保存了行的建立時間和行的刪除時間,這個存儲的時間值實際是系統版本號。每開啓一個新事務,系統版本號都會自動遞增,而某個事務開始時刻的系統版本號就會做爲該事務的版本號,用來和查詢獲得的每行記錄的版本號進行比較。這種描述是否是有點似曾相識的味道,沒錯,這種併發實現和咱們日常的用時間戳或版本號實現樂觀鎖大同小異。不一樣的是,MVCC在修改數據行時是對其副本進行修改,以此來保證各個事務互不干擾,在保存時比較版本號無誤以後纔會覆蓋原來的記錄。怎樣纔算無誤呢?特此附上比較規則:版本控制
1,select操做事務
a,行的系統版本號要小於或等於事務的系統版本號date
b,行的刪除版本號要麼未定義,要麼大於當前事務版本號select
2,insert操做時間戳
爲新插入的每一行保存當前系統版本號做爲行版本號數據
3,delete操做項目
爲刪除的每一行保存當前系統版本號做爲行刪除標識 查詢
4,update
插入一行新記錄,保存當前系統版本號做爲行版本號,同時保存當前系統版本號到原來的行做爲刪除標識