關於MVCC的原理,在《我想進大廠》之mysql奪命連環13問寫過一次,可是當時寫的其實並不許確,這個理解能夠應付面試,幫助快速理解,可是他的真正實現原理我想再次拿出來講一說。mysql
如下先引用我以前寫過的那篇中的內容,能夠快速理解,建議先簡單看看。面試
要說幻讀,首先要了解MVCC,MVCC叫作多版本併發控制,實際上就是保存了數據在某個時間節點的快照。sql
咱們每行數據實際上隱藏了兩列,建立時間版本號,過時(刪除)時間版本號,每開始一個新的事務,版本號都會自動遞增。併發
仍是拿上面的user表舉例子,假設咱們插入兩條數據,他們實際上應該長這樣。編輯器
這時候假設小明去執行查詢,此時current_version=3spa
select * from user where id<=3;
同時,小紅在這時候開啓事務去修改id=1的記錄,current_version=4日誌
update user set name='張三三' where id=1;
執行成功後的結果是這樣的code
若是這時候還有小黑在刪除id=2的數據,current_version=5,執行後結果是這樣的。blog
因爲MVCC的原理是查找建立版本小於或等於當前事務版本,刪除版本爲空或者大於當前事務版本,小明的真實的查詢應該是這樣事務
select * from user where id<=3 and create_version<=3 and (delete_version>3 or delete_version is null);
因此小明最後查詢到的id=1的名字仍是'張三',而且id=2的記錄也能查詢到。這樣作是爲了保證事務讀取的數據是在事務開始前就已經存在的,要麼是事務本身插入或者修改的。
事實上,上述的說法只是簡化版的理解,真正的MVCC用於讀已提交和可重複讀級別的控制,主要經過undo log日誌版本鏈和read view來實現。
每條數據隱藏的兩個字段也並非建立時間版本號
和過時(刪除)時間版本號
,而是roll_pointer
和trx_id
。
roll_pointer指向更新事務以前生成的undo log,undo log用於事務的回滾,保證事務的原子性。
trx_id就是最近一次更新數據的事務ID。
以上述例子來舉例,最初插入兩條數據,真實的狀況是這樣,由於第一次插入數據沒有undo log,因此roll_pointer指向一個空的undo log。
這時候假設小明去執行查詢,就會開啓一個read view,read view包含幾個重要的東西。
小明來執行查詢了,當前事務ID=3
select * from user where id<=3;
小紅在這時候開啓事務去修改id=1的記錄,事務ID=4
update user set name='張三三' where id=1;
這時候小明的read view是這樣。
m_ids=[3,4]
low_limit_id=3
up_limit_id=5
creator_trx_id=3
因此,小明在執行查詢的時候,會去判斷當前這條數據的trx_id<read view的low_limit_id,顯然都小於,因此小明會正常查詢到id=1,2的兩條記錄,而不會受到小紅修改的影響。
這時候,小紅的修改也完成了,小紅數據因而就變成了這樣。
若是小明再次去查詢的話,就會發現如今的trx_id>read view的low_limit_id,也就是4>3,不符合條件,同時發現如今的trx_id=4在low_limit_id和up_limit_id [3,5]之間,而且trx_id=4在m_ids=[3,4]之中,因此就會根據roll_pointer指向的undo log去查找,trx_id=1小於如今的low_limit_id=3,符合條件,就找到了上一個版本name=張三的記錄。
若是這時候小明本身去修改這條記錄的值,把名字改爲張五,結果就是這樣。
而後小明去查詢的話,就會發現當前的trx_id=3就是本身的creator_trx_id,就是本身,那麼就直接返回這條數據。
因此,咱們能夠先總結下幾種狀況:
根據上面闡述的原理,你可能發現了,這是可重複讀下的實現啊,保證每次讀取到的數據都是一致的。
那麼,若是是讀已提交級別下,這個是怎麼實現的?
其實很簡單,在上面的原理解釋中,我都是假設每次查詢的時候生成了read view,後續並無從新生成。
而讀已提交級別下,則是每次查詢都會生成一次read view。
以上述小紅修改過張三後的場景來舉例。
在可重複度級別下,因爲trx_id>low_limit,trx_id還在[low_limit_id,up_limit_id]範圍以內,而且trx_id在m_ids中,知足咱們上述的條件2,因此就會根據roll_pointer找到以前的版本記錄,保證可重複讀。
而在讀已提交的級別下,從新生成了read view,這時候trx_id不在m_ids之中,說明事務已經提交,因此能夠直接返回這條數據,因此查到的數據就是小紅修改後的name=張三三
的數據了。
我是艾小仙,我認可我浪了,我以前竟然還想浪,我覺得年沒過幾天,結果發現最近一次技術文更新是在2月2號。
我哭,因此,我肝了3個小時,痛定思痛,結束了個人短暫的王者生涯。
你們以爲還行的話,點個在看,設個星標可好?
我要回到正常更新的頻率中來。
- END -