具體細(xì)節(jié) 請去掘金購買《MySQL 是怎樣運行的:從根兒上理解 MySQL》
事務(wù)隔離級別
事務(wù)并發(fā)執(zhí)行遇到的問題
- 1.臟寫(Dirty Write):一個事務(wù)修改了另一個未提交事務(wù)修改過的數(shù)據(jù)
- 2.臟讀(Dirty Read):一個事務(wù)讀到了另一個未提交事務(wù)修改過的數(shù)據(jù)
- 3.不可重復(fù)讀(Non-Repeatable Read):個事務(wù)只能讀到另一個已經(jīng)提交的事務(wù)修改過的數(shù)據(jù)口注,并且其他事務(wù)每對該數(shù)據(jù)進(jìn)行一次修改并提交后誊辉,該事務(wù)都能查詢得到最新值
- 4.幻讀(Phantom):一個事務(wù)先根據(jù)某些條件查詢出一些記錄,之后另一個事務(wù)又向表中插入了符合這些條件的記錄,原先的事務(wù)再次按照該條件查詢時,能把另一個事務(wù)插入的記錄也讀出來
- 5.幻讀強調(diào)的是一個事務(wù)按照某個相同條件多次讀取記錄時,后讀取時讀到了之前沒有讀到的記錄,如果數(shù)據(jù)減少了 不屬于幻讀澳盐,應(yīng)該
歸類于不可重復(fù)讀。 - 6.上述問題的嚴(yán)重性:臟寫 > 臟讀 > 不可重復(fù)讀 > 幻讀
SQL標(biāo)準(zhǔn)中的四種隔離級別
- 1.READ UNCOMMITTED:未提交讀令宿。
- 2.READ COMMITTED:已提交讀叼耙。
- 3.REPEATABLE READ:可重復(fù)讀。
- 4.SERIALIZABLE:可串行化粒没。
SQL標(biāo)準(zhǔn)中規(guī)定筛婉,針對不同的隔離級別,并發(fā)事務(wù)可以發(fā)生不同嚴(yán)重程度的問題
- 1.READ UNCOMMITTED可能發(fā)生的問題:臟讀 癞松, 不可重復(fù)讀 爽撒,幻讀
- 2.READ COMMITTED 可能發(fā)生的問題: 不可重復(fù)讀 ,幻讀
- 3.REPEATABLE READ可能發(fā)生的問題:幻讀(但是MySql實際中是不存在幻讀的)
- 4.SERIALIZABLE不會發(fā)生問題
事務(wù)的范圍
- 1.SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;只對執(zhí)行完該語句之后產(chǎn)生的會話起作用响蓉。當(dāng)前已經(jīng)存在的會話無效鸿脓。
- 2.SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;對當(dāng)前會話的所有后續(xù)的事務(wù)有效这难,該語句可以在已經(jīng)開啟的事務(wù)中間執(zhí)行螟蝙,但不會影響當(dāng)前正在執(zhí)行的事務(wù)限番。,如果在事務(wù)之間執(zhí)行想幻,則對后續(xù)的事務(wù)有效粱栖。
- 3.默認(rèn)情況下只對當(dāng)前回話中的下一個即將開啟的事務(wù)有效,下一個事務(wù)執(zhí)行完畢后后續(xù)事務(wù)恢復(fù)到默認(rèn)的隔離級別
該語句不能再已經(jīng)開啟的事務(wù)中間執(zhí)行 - 4.通過系統(tǒng)變量transaction-isolation來指定
MVCC原理
版本鏈
- 1.roll_pointer:每次對某條聚簇索引記錄進(jìn)行改動時脏毯,都會把舊的版本寫入到undo日志中然后這個隱藏列就相當(dāng)于一個指針闹究,可以通過它來找到該記錄修改前的信息。
- 2.每條undo日志也都有一個roll_pointer屬性,可以將這些undo日志都連起來抄沮,串成一個鏈表
- 3.對該記錄每次更新后跋核,都會將舊值放到一條undo日志中岖瑰,就算是該記錄的一個舊版本,隨著更新次數(shù)的增多砂代,所有的版本都會被roll_pointer屬性連接成一個鏈表蹋订,我們把這個鏈表稱之為版本鏈
- 4.版本鏈的頭節(jié)點就是當(dāng)前記錄最新的值。另外刻伊,每個版本中還包含生成該版本時對應(yīng)的事務(wù)id
ReadView作用
- 1.對于使用READ COMMITTED和REPEATABLE READ隔離級別的事務(wù)來說露戒,都必須保證讀到已經(jīng)提交了的事務(wù)修改過的記錄
- 2.核心問題就是:需要判斷一下版本鏈中的哪個版本是當(dāng)前事務(wù)可見的,因此提出ReadView
ReadView的構(gòu)成
- 1.m_ids:表示在生成ReadView時當(dāng)前系統(tǒng)中活躍的讀寫事務(wù)的事務(wù)id列表。
- 2.min_trx_id:m_ids中的最小值捶箱。
- 3.max_trx_id:表示生成ReadView時系統(tǒng)中應(yīng)該分配給下一個事務(wù)的id值
- 4.creator_trx_id:表示生成該ReadView的事務(wù)的事務(wù)id智什。
- 5.只有在對表中的記錄做改動時(執(zhí)行INSERT、DELETE丁屎、UPDATE這些語句時)才會為事務(wù)分配事務(wù)id荠锭,否則在一個只讀事務(wù)中的事務(wù)id值都默認(rèn)為0。
訪問某條記錄的時候判斷版本是否可見的步驟如下(建立在可重復(fù)讀和讀已提交晨川,對于某條記錄的并發(fā)執(zhí)行是通過鎖保證的):
- 1.如果被訪問版本的trx_id屬性值與ReadView中的creator_trx_id值相同证九,意味著當(dāng)前事務(wù)在訪問它自己修改過的記錄,所以該版本可以被當(dāng)前事務(wù)訪問共虑。
- 2.如果被訪問版本的trx_id屬性值小于ReadView中的min_trx_id值愧怜,表明生成該版本的事務(wù)在當(dāng)前事務(wù)生成ReadView前已經(jīng)提交,所以該版本可以被當(dāng)前事務(wù)訪問妈拌。
- 3.如果被訪問版本的trx_id屬性值大于ReadView中的max_trx_id值拥坛,表明生成該版本的事務(wù)在當(dāng)前事務(wù)生成ReadView后才開啟,所以該版本不可以被當(dāng)前事務(wù)訪問尘分。
- 4.如果被訪問版本的trx_id屬性值在ReadView的min_trx_id和max_trx_id之間猜惋,那就需要判斷一下trx_id屬性值是不是在m_ids列表中,如果在音诫,說明創(chuàng)建ReadView時生成該版本的事務(wù)還是活躍的惨奕,該版本不可以被訪問;如果不在竭钝,說明創(chuàng)建ReadView時生成該版本的事務(wù)已經(jīng)被提交,該版本可以被訪問雹洗。
- 5.起初都是尋找當(dāng)前記錄香罐,然后當(dāng)前記錄不行在順著版本鏈找下一個該記錄的版本。如果都不可見則查詢結(jié)果不包含該記錄
READ COMMITTED和REPEATABLE READ隔離級別的的一個非常大的區(qū)別
- 1.它們生成ReadView的時機(jī)不同
- 2.READ COMMITTED是一個事務(wù)中只要調(diào)用select就重新生成一個ReadView
- 3.REPEATABLE READ只能在第一次select生成ReadView
關(guān)于purge
- 1.為了支持MVCC时肿,對于delete mark操作來說庇茫,僅僅是在記錄上打一個刪除標(biāo)記,并沒有真正將它刪除掉螃成。
- 2.隨著系統(tǒng)的運行旦签,在確定系統(tǒng)中包含最早產(chǎn)生的那個ReadView的事務(wù)不會再訪問某些update undo日志以及被打了刪除標(biāo)記的記錄后查坪,有一個后臺運行的purge線程會把它們真正的刪除掉。