MySql事務(wù)-版本鏈

以下所有的知識(shí)都是基于 InnoDB 的,因?yàn)镸yISAM不?持事務(wù)。
事務(wù)的隔離級(jí)別四種
讀未提交(READ UNCOMMITTED) :?個(gè)事務(wù)還沒(méi)提交時(shí),它做的變更就能被別的事務(wù)看到。
讀提交(READ COMMITTED) :?個(gè)事務(wù)提交之后,它做的變更才會(huì)被其他事務(wù)看到。
可重復(fù)讀(REPEATABLE READ) :?個(gè)事務(wù)執(zhí)?過(guò)程中看到的數(shù)據(jù),總是跟這個(gè)事務(wù)在啟動(dòng)時(shí)看到的
數(shù)據(jù)是?致的。當(dāng)然在可重復(fù)讀隔離級(jí)別下,未提交變更對(duì)其他事務(wù)也是不可?的。
串?化(SERIALIZABLE) :對(duì)于同??記錄,“寫”會(huì)加“寫鎖”,“讀”會(huì)加“讀鎖”,當(dāng)出現(xiàn)讀寫鎖沖突
的時(shí)候,后訪問(wèn)的事務(wù)必須等前?個(gè)事務(wù)執(zhí)?完成,才能繼續(xù)執(zhí)?。

隔離級(jí)別解決了哪些問(wèn)題?家也應(yīng)該都是知道的分別有:
臟讀(dirty read) :如果?個(gè)事務(wù)讀到了另?個(gè)未提交事務(wù)修改過(guò)的數(shù)據(jù)

image.png

不可重復(fù)讀(non-repeatable read) :如果?個(gè)事務(wù)只能讀到另?個(gè)已經(jīng)提交的事務(wù)修改過(guò)的數(shù)
據(jù),并且其他事務(wù)每對(duì)該數(shù)據(jù)進(jìn)??次修改并提交后,該事務(wù)都能查詢得到最新值。

image.png

幻讀(phantom read) :如果?個(gè)事務(wù)先根據(jù)某些條件查詢出?些記錄,之后另?個(gè)事務(wù)?向表中
插?了符合這些條件的記錄,原先的事務(wù)再次按照該條件查詢時(shí),能把另?個(gè)事務(wù)插?的記錄也讀
出來(lái)

image.png

我們可以通過(guò)下邊的語(yǔ)句修改事務(wù)的隔離級(jí)別

SET [GLOBAL|SESSION] TRANSACTION ISOLATION LEVEL level;//等級(jí)就是上?的?種

在 可重復(fù)讀 隔離級(jí)別下,事務(wù)在啟動(dòng)的時(shí)候就“拍了個(gè)快照”,注意,這個(gè)快照是基于整庫(kù)的。
你肯定會(huì)說(shuō),這怎么可能?如果?個(gè)庫(kù)有100G,那么我啟動(dòng)?個(gè)事務(wù),MySQL就要拷?100G的數(shù)據(jù)出
來(lái),這個(gè)過(guò)程得多慢啊,這誰(shuí)頂?shù)米“??可是你回頭?想,平時(shí)的事務(wù)執(zhí)?起來(lái)不是很快么

實(shí)際上,數(shù)據(jù)庫(kù)并不需要拷?出這100G的數(shù)據(jù),那快照怎么實(shí)現(xiàn)的?
InnoDB??每個(gè)事務(wù)有?個(gè)唯?的事務(wù)ID,叫作 transaction id ,它是在事務(wù)開(kāi)始的時(shí)候向InnoDB
的事務(wù)系統(tǒng)申請(qǐng)的,是按申請(qǐng)順序嚴(yán)格遞增的

每?數(shù)據(jù)也都是有多個(gè)版本的,每次事務(wù)更新數(shù)據(jù)的時(shí)候,都會(huì)?成?個(gè)新的數(shù)據(jù)版本,并且把
transaction id 賦值給這個(gè)數(shù)據(jù)版本的事務(wù)ID,記為** row trx_id** 。同時(shí),舊的數(shù)據(jù)版本要保留,并
且在新的數(shù)據(jù)版本中,能夠有信息可以直接拿到它。
也就是說(shuō),數(shù)據(jù)表中的??記錄,其實(shí)可能有多個(gè)版本(row),每個(gè)版本有??的 row trx_id 。
這是?個(gè)隱藏列,還有另外?個(gè) roll_pointer :每次對(duì)某條聚簇索引記錄進(jìn)?改動(dòng)時(shí),都會(huì)把舊的版
本寫?到 undo?志 中,然后這個(gè)隱藏列就相當(dāng)于?個(gè)指針,可以通過(guò)它來(lái)找到該記錄修改前的信息
兩者都在InnoDB的聚簇索引中,?概就?這樣:

image.png

undo log 的回滾機(jī)制也是依靠這個(gè)版本鏈,每次對(duì)記錄進(jìn)?改動(dòng),都會(huì)記錄?條undo?志,每條
undo?志也都有?個(gè) roll_pointer 屬性(INSERT操作對(duì)應(yīng)的undo?志沒(méi)有該屬性,因?yàn)樵撚涗洸](méi)
有更早的版本),可以將這些undo?志都連起來(lái),串成?個(gè)鏈表,所以現(xiàn)在的情況就像下圖?樣

image.png

接下來(lái)可以說(shuō)?下事務(wù)隔離級(jí)別和MVCC的關(guān)系了,下?的例?是?個(gè)版本鏈,事務(wù)id?家可以看出,
三個(gè)事務(wù)分別作了不同的事情。
在 讀提交 隔離級(jí)別下,這個(gè)視圖是在每個(gè)SQL語(yǔ)句開(kāi)始執(zhí)?的時(shí)候創(chuàng)建的,在這個(gè)隔離級(jí)別下,事務(wù)在
每次查詢開(kāi)始時(shí)都會(huì)?成?個(gè)獨(dú)?的ReadView。

image.png

可重復(fù)讀,在第?次讀取數(shù)據(jù)時(shí)?成?個(gè)ReadView,對(duì)于使? REPEATABLE READ 隔離級(jí)別的事務(wù)來(lái)
說(shuō),只會(huì)在第?次執(zhí)?查詢語(yǔ)句時(shí)?成?個(gè) ReadView ,之后的查詢就不會(huì)重復(fù)?成了,所以?個(gè)事務(wù)
的查詢結(jié)果每次都是?樣的。

image.png

這?需要注意的是, 讀未提交 隔離級(jí)別下直接返回記錄上的最新值,沒(méi)有視圖概念,也就是圖中丙丙那
?欄,臟讀,幻讀,不可重復(fù)讀都有可能發(fā)?。? 串?化 隔離級(jí)別下直接?加鎖的?式來(lái)避免并?訪問(wèn)。

mvcc??跟事務(wù)隔離級(jí)別相關(guān)的,只有可重復(fù)讀和讀已提交這兩種
大部分公司數(shù)據(jù)庫(kù)隔離級(jí)別默認(rèn)都是讀已提交,不過(guò)我們會(huì)在?些場(chǎng)景開(kāi)啟可重復(fù)讀,序列化很少?

可重復(fù)讀我們之前都是在跟訂單?額相關(guān)的場(chǎng)景去開(kāi)啟的,還有很多數(shù)據(jù)修改過(guò)程也會(huì)?可重復(fù)度,因
為很多值是需要查詢出來(lái),依據(jù)那個(gè)值做別的操作的,如果多次查詢的結(jié)果值不?樣,那后者也會(huì)受到
影響。
序列化 被稱為數(shù)據(jù)庫(kù)隔離級(jí)別的 ??標(biāo)準(zhǔn) ,它是絕?多數(shù)商業(yè)數(shù)據(jù)庫(kù)系統(tǒng)中提供的最?隔離級(jí)別,?
些?度?泛部署的系統(tǒng)甚??法提供隔離級(jí)別與可序列化?樣?,?融的場(chǎng)景居多,性能也是最差的,
但是銀?取錢你會(huì)在乎那?秒么?
有沒(méi)有發(fā)現(xiàn)銀?的ATM響應(yīng)速度特別慢,他們的場(chǎng)景都是很嚴(yán)密的,各種事務(wù),鎖,都是結(jié)合的,就是
為了保證結(jié)果的準(zhǔn)確性。
?家可以?這個(gè)命令去看看??公司或者??現(xiàn)在使?的數(shù)據(jù)庫(kù)的隔離級(jí)別

show variables
image.png

參考:《MySQL 是怎樣運(yùn)?的:從根?上理解 MySQL》、《?性能MySQL》、《 MySQL 實(shí)戰(zhàn)45 講》

總結(jié)

從上邊的描述中我們可以看出來(lái),所謂的 MVCC(Multi-Version Concurrency Control ,多版本并發(fā)控
制) 指的就是在使? 讀已提交(READ COMMITTD)、可重復(fù)讀(REPEATABLE READ) 這兩種隔離級(jí)別的事務(wù)
在執(zhí)?普通的SELECT操作時(shí)訪問(wèn)記錄的版本鏈的過(guò)程,這樣?可以使不同事務(wù)的讀-寫、寫-讀操作并
發(fā)執(zhí)?,從?提升系統(tǒng)性能。
這兩個(gè)隔離級(jí)別的?個(gè)很?不同就是: ?成ReadView的時(shí)機(jī)不同 ,READ COMMITTD在每?次進(jìn)?普通
SELECT操作前都會(huì)?成?個(gè)ReadView,?REPEATABLE READ只在第?次進(jìn)?普通SELECT操作前?
成?個(gè)ReadView,數(shù)據(jù)的可重復(fù)讀其實(shí)就是ReadView的重復(fù)使?。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容