以下所有的知識都是基于 InnoDB 的,因為MyISAM不?持事務(wù)芜繁。
事務(wù)的隔離級別四種
讀未提交(READ UNCOMMITTED) :?個事務(wù)還沒提交時,它做的變更就能被別的事務(wù)看到。
讀提交(READ COMMITTED) :?個事務(wù)提交之后泰鸡,它做的變更才會被其他事務(wù)看到滞乙。
可重復(fù)讀(REPEATABLE READ) :?個事務(wù)執(zhí)?過程中看到的數(shù)據(jù)妄讯,總是跟這個事務(wù)在啟動時看到的
數(shù)據(jù)是?致的孩锡。當(dāng)然在可重復(fù)讀隔離級別下,未提交變更對其他事務(wù)也是不可?的亥贸。
串?化(SERIALIZABLE) :對于同??記錄躬窜,“寫”會加“寫鎖”,“讀”會加“讀鎖”炕置,當(dāng)出現(xiàn)讀寫鎖沖突
的時候荣挨,后訪問的事務(wù)必須等前?個事務(wù)執(zhí)?完成,才能繼續(xù)執(zhí)?朴摊。
隔離級別解決了哪些問題?家也應(yīng)該都是知道的分別有:
臟讀(dirty read) :如果?個事務(wù)讀到了另?個未提交事務(wù)修改過的數(shù)據(jù)
不可重復(fù)讀(non-repeatable read) :如果?個事務(wù)只能讀到另?個已經(jīng)提交的事務(wù)修改過的數(shù)
據(jù)默垄,并且其他事務(wù)每對該數(shù)據(jù)進(jìn)??次修改并提交后,該事務(wù)都能查詢得到最新值甚纲。
幻讀(phantom read) :如果?個事務(wù)先根據(jù)某些條件查詢出?些記錄口锭,之后另?個事務(wù)?向表中
插?了符合這些條件的記錄,原先的事務(wù)再次按照該條件查詢時介杆,能把另?個事務(wù)插?的記錄也讀
出來
我們可以通過下邊的語句修改事務(wù)的隔離級別
SET [GLOBAL|SESSION] TRANSACTION ISOLATION LEVEL level;//等級就是上?的?種
在 可重復(fù)讀 隔離級別下鹃操,事務(wù)在啟動的時候就“拍了個快照”,注意春哨,這個快照是基于整庫的荆隘。
你肯定會說,這怎么可能赴背?如果?個庫有100G椰拒,那么我啟動?個事務(wù),MySQL就要拷?100G的數(shù)據(jù)出
來凰荚,這個過程得多慢啊燃观,這誰頂?shù)米“”闵靠墒悄慊仡^?想仪壮,平時的事務(wù)執(zhí)?起來不是很快么
實際上,數(shù)據(jù)庫并不需要拷?出這100G的數(shù)據(jù)胳徽,那快照怎么實現(xiàn)的积锅?
InnoDB??每個事務(wù)有?個唯?的事務(wù)ID,叫作 transaction id 养盗,它是在事務(wù)開始的時候向InnoDB
的事務(wù)系統(tǒng)申請的缚陷,是按申請順序嚴(yán)格遞增的
每?數(shù)據(jù)也都是有多個版本的,每次事務(wù)更新數(shù)據(jù)的時候往核,都會?成?個新的數(shù)據(jù)版本箫爷,并且把
transaction id 賦值給這個數(shù)據(jù)版本的事務(wù)ID,記為** row trx_id** 。同時虎锚,舊的數(shù)據(jù)版本要保留硫痰,并
且在新的數(shù)據(jù)版本中,能夠有信息可以直接拿到它窜护。
也就是說效斑,數(shù)據(jù)表中的??記錄,其實可能有多個版本(row)柱徙,每個版本有??的 row trx_id 缓屠。
這是?個隱藏列,還有另外?個 roll_pointer :每次對某條聚簇索引記錄進(jìn)?改動時护侮,都會把舊的版
本寫?到 undo?志 中敌完,然后這個隱藏列就相當(dāng)于?個指針,可以通過它來找到該記錄修改前的信息
兩者都在InnoDB的聚簇索引中羊初,?概就?這樣:
undo log 的回滾機(jī)制也是依靠這個版本鏈滨溉,每次對記錄進(jìn)?改動,都會記錄?條undo?志长赞,每條
undo?志也都有?個 roll_pointer 屬性(INSERT操作對應(yīng)的undo?志沒有該屬性晦攒,因為該記錄并沒
有更早的版本),可以將這些undo?志都連起來涧卵,串成?個鏈表,所以現(xiàn)在的情況就像下圖?樣
接下來可以說?下事務(wù)隔離級別和MVCC的關(guān)系了腹尖,下?的例?是?個版本鏈柳恐,事務(wù)id?家可以看出,
三個事務(wù)分別作了不同的事情热幔。
在 讀提交 隔離級別下乐设,這個視圖是在每個SQL語句開始執(zhí)?的時候創(chuàng)建的,在這個隔離級別下绎巨,事務(wù)在
每次查詢開始時都會?成?個獨?的ReadView近尚。
可重復(fù)讀,在第?次讀取數(shù)據(jù)時?成?個ReadView场勤,對于使? REPEATABLE READ 隔離級別的事務(wù)來
說戈锻,只會在第?次執(zhí)?查詢語句時?成?個 ReadView ,之后的查詢就不會重復(fù)?成了和媳,所以?個事務(wù)
的查詢結(jié)果每次都是?樣的格遭。
這?需要注意的是, 讀未提交 隔離級別下直接返回記錄上的最新值留瞳,沒有視圖概念拒迅,也就是圖中丙丙那
?欄,臟讀,幻讀璧微,不可重復(fù)讀都有可能發(fā)?作箍。? 串?化 隔離級別下直接?加鎖的?式來避免并?訪問。
mvcc??跟事務(wù)隔離級別相關(guān)的前硫,只有可重復(fù)讀和讀已提交這兩種
大部分公司數(shù)據(jù)庫隔離級別默認(rèn)都是讀已提交胞得,不過我們會在?些場景開啟可重復(fù)讀,序列化很少?
可重復(fù)讀我們之前都是在跟訂單?額相關(guān)的場景去開啟的开瞭,還有很多數(shù)據(jù)修改過程也會?可重復(fù)度懒震,因
為很多值是需要查詢出來,依據(jù)那個值做別的操作的嗤详,如果多次查詢的結(jié)果值不?樣个扰,那后者也會受到
影響。
序列化 被稱為數(shù)據(jù)庫隔離級別的 ??標(biāo)準(zhǔn) 葱色,它是絕?多數(shù)商業(yè)數(shù)據(jù)庫系統(tǒng)中提供的最?隔離級別递宅,?
些?度?泛部署的系統(tǒng)甚??法提供隔離級別與可序列化?樣?,?融的場景居多苍狰,性能也是最差的办龄,
但是銀?取錢你會在乎那?秒么?
有沒有發(fā)現(xiàn)銀?的ATM響應(yīng)速度特別慢淋昭,他們的場景都是很嚴(yán)密的俐填,各種事務(wù),鎖翔忽,都是結(jié)合的英融,就是
為了保證結(jié)果的準(zhǔn)確性。
?家可以?這個命令去看看??公司或者??現(xiàn)在使?的數(shù)據(jù)庫的隔離級別
show variables
參考:《MySQL 是怎樣運?的:從根?上理解 MySQL》歇式、《?性能MySQL》驶悟、《 MySQL 實戰(zhàn)45 講》
總結(jié)
從上邊的描述中我們可以看出來,所謂的 MVCC(Multi-Version Concurrency Control 材失,多版本并發(fā)控
制) 指的就是在使? 讀已提交(READ COMMITTD)痕鳍、可重復(fù)讀(REPEATABLE READ) 這兩種隔離級別的事務(wù)
在執(zhí)?普通的SELECT操作時訪問記錄的版本鏈的過程,這樣?可以使不同事務(wù)的讀-寫龙巨、寫-讀操作并
發(fā)執(zhí)?笼呆,從?提升系統(tǒng)性能。
這兩個隔離級別的?個很?不同就是: ?成ReadView的時機(jī)不同 旨别,READ COMMITTD在每?次進(jìn)?普通
SELECT操作前都會?成?個ReadView抄邀,?REPEATABLE READ只在第?次進(jìn)?普通SELECT操作前?
成?個ReadView,數(shù)據(jù)的可重復(fù)讀其實就是ReadView的重復(fù)使?昼榛。