這個要從MySql - 對update是怎麼處理的的undo日誌文件提及。
咱們對數據進行修改以前,都會把數據寫入到undo日誌中,若是對一條數據作了屢次修改,那這些數據就會經過鏈表關聯起來。
MySql - 一條語句是怎麼插入磁盤的提到了一條數據的結構,咱們這裏就用DB_TRX_ID事務ID,DB_ROLL_PTR事務回滾以及具體的數據DATA來簡化一條數據,下面用簡單的例子講解一下這個undo日誌鏈表。segmentfault
插入一條數據DATA爲,AAA,此時的DB_TRX_ID爲1,DB_ROLL_PTR爲空,以下圖:
多線程
修改這個數據DATA爲BBB,此時的DB_TRX_ID爲2,DB_ROLL_PTR指向修改前的數據,以下圖:
spa
修改這個數據DATA爲CCC,此時的DB_TRX_ID爲3,DB_ROLL_PTR指向修改前的數據,以下圖:
線程
MySql是支持多線程的,因此當多個事務提交的時候,其中一個事務就會建立一個ReadView。
ReadView的結構以下:日誌
max_trx_id:最大的事務id+1
咱們一樣用一個例子來講明這個機制。
假設事務1插入了DATA爲AAA後,事務2和事務3對這條數據進行了查詢和修改。事務
事務2建立了ReadView。因此ReadView以下:get
max_trx_id爲4。
同步
事務2查詢了這條語句。
事務2首先會判斷min_trx_id(2)和這條數據的DB_TRX_ID(1),此時2比1大,說明ReadView裏的事務都是在當前數據的事務後建立的。咱們固然能夠讀取以前的事務提交的數據。
此時事務2直接讀取這條數據的DATA,AAA。it
事務3修改了這條語句,DATA改成BBB。
事務3也會判斷min_trx_id(2)和這條數據的DB_TRX_ID(1),發現是以前事務提交 的數據,因此他就直接修改了此數據。
class
事務2繼續查詢了這條語句。
事務2發現DB_TRX_ID(3)比min_trx_id(2)大,可是比max_trx_id(4)小,同時在m_ids(2,3)中,因此知道了這個修改數據的事務是跟本身在同一個ReadView中的,那他就不能讀取當前事務的數據,就根據DB_ROLL_PTR讀取上一個數據。
因此又讀到了DB_TRX_ID(1)的DATA的值AAA。這就是可重複讀。
事務4修改了這條語句,DATA改成CCC。
事務4會生成新的ReadView,而後發現DB_TRX_ID(3)是以前事務提交 的數據,因此他就直接修改了此數據。
事務2繼續查詢這條語句,他對比DB_TRX_ID(4)和max_trx_id(4),發現這個數據被比本身後面的事務提交了,因此他也不能看到這個事務提交的數據,因而他就順着鏈表找到DB_TRX_ID(3),判斷同步驟6,最終仍是找到了DB_TRX_ID(1)的DATA爲AAA的數據。以上例子能夠看到,ReadView機制能夠保證能夠讀取到以前提交事務的數據,可是讀取不到一塊兒執行的事務以及以後的事務提交的數據。