原文:zhuanlan.zhihu.com/p/55872397
做者:柳樹html
上一講最後拋出了一個問題,Mysql可重複讀的「快照」究竟是啥?mysql
是對當前數據的全量拷貝嗎?每開啓一個事務,都要把當前數據庫的數據拷貝一份出來?sql
很明顯不是。數據庫
一方面,這樣作太消耗內存了,另外一方面,這樣會很慢。數組
那麼Mysql是如何實現「快照」的呢?session
咱們仍是用上一講的例子:併發
咱們已經知道,Session A在第二次select時,查詢到的結果和第一次select時同樣,也就是說,Session B的update,對Session A來講,不可見,Mysql是如何作到的呢?3d
很簡單,也很絕妙 —— 數據版本,也就是咱們常說的MVCC,多版本併發控制。cdn
下面講具體實現。htm
Innodb裏面,每行數據,均可以有多個版本,每一個版本都有一個字段trx_id,記錄生成這個版本的事務的ID。
假設一開始,id=1這行數據,只有一個版本,trx_id是90,意味着生成這個版本的事務ID是90:
這時候Session A開始了,從上一講,咱們已經知道,begin時並不會生成快照,快照在第一次select時纔會生成,那麼第一次select時,session A都作了什麼呢?
session A只須要作一件事:用一個數組,來記錄當前活躍的事務ID。
假設session A的事務ID是97,當前還有另外兩個事務,事務ID是9四、96,因此session A會生成一個[94,96,97]的數組。
這個數組有什麼用?後面你就知道了。
接着,session B執行了update語句,來更新id=1這一行數據,給這一行數據生成一個新的版本,假設session B的事務ID是98,所以這行數據就有了兩個版本:
這時候,session A又來select了,當前版本是session B生成的,那session A是如何找到以前的版本的呢?
這時候,session A一開始生成的事務數組就派上用場了,session A的事務數組是[94,96,97],最小事務ID是94,最大事務ID是97,因此,當它遇到一行數據時,會先判斷這行數據的版本號X:
好,如今session A開始遍歷id=1這行數據的全部版本:
當前版本是98,大於97,因此不可見,繼續看上一個版本;
再往上,版本是90,小於94,可見,就它了,因此session A select出來的id=1的數據,c的值是1。
固然,這樣的人肉判斷實在太麻煩了,在《Mysql實戰45講》裏,丁奇給出了這樣一個**「等價判斷」可見性的原則**:
這其實就是可重複讀的想要實現的效果。
最後再給一個複雜點的例子,你們運用上面的原則,來預測sql語句的查詢結果:
小結一下:
問題又來了,這些不一樣版本的數據,是物理存在於內存或者磁盤中的嗎?