這是一個(gè)相當(dāng)基礎(chǔ)的問題
SQL標(biāo)準(zhǔn)定義了4類隔離級(jí)別想虎,包括了一些具體規(guī)則,用來限定事務(wù)內(nèi)外的哪些改變是可見的,哪些是不可見的放棒。低級(jí)別的隔離級(jí)一般支持更高的并發(fā)處理痰催,并擁有更低的系統(tǒng)開銷兜辞。
Read Uncommitted(讀取未提交內(nèi)容)
在該隔離級(jí)別,所有事務(wù)都可以看到其他未提交事務(wù)的執(zhí)行結(jié)果夸溶。本隔離級(jí)別很少用于實(shí)際應(yīng)用逸吵,因?yàn)樗男阅芤膊槐绕渌?jí)別好多少。讀取未提交的數(shù)據(jù)缝裁,也被稱之為臟讀(Dirty Read)扫皱。
Read Committed(讀取提交內(nèi)容)
這是大多數(shù)數(shù)據(jù)庫系統(tǒng)的默認(rèn)隔離級(jí)別(但不是MySQL默認(rèn)的)足绅。它滿足了隔離的簡單定義:一個(gè)事務(wù)只能看見已經(jīng)提交事務(wù)所做的改變。這種隔離級(jí)別 也支持所謂的不可重復(fù)讀(Nonrepeatable Read)韩脑,因?yàn)橥皇聞?wù)的其他實(shí)例在該實(shí)例處理其間可能會(huì)有新的commit氢妈,所以同一select可能返回不同結(jié)果。
Repeatable Read(可重讀)
這是MySQL的默認(rèn)事務(wù)隔離級(jí)別段多,它確保同一事務(wù)的多個(gè)實(shí)例在并發(fā)讀取數(shù)據(jù)時(shí)首量,會(huì)看到同樣的數(shù)據(jù)行。不過理論上进苍,這會(huì)導(dǎo)致另一個(gè)棘手的問題:幻讀 (Phantom Read)加缘。簡單的說,幻讀指當(dāng)用戶讀取某一范圍的數(shù)據(jù)行時(shí)觉啊,另一個(gè)事務(wù)又在該范圍內(nèi)插入了新行拣宏,當(dāng)用戶再讀取該范圍的數(shù)據(jù)行時(shí),會(huì)發(fā)現(xiàn)有新的“幻影” 行杠人。InnoDB和Falcon存儲(chǔ)引擎通過多版本并發(fā)控制(MVCC勋乾,Multiversion Concurrency Control)機(jī)制解決了該問題。
Serializable(可串行化)
這是最高的隔離級(jí)別嗡善,它通過強(qiáng)制事務(wù)排序辑莫,使之不可能相互沖突,從而解決幻讀問題滤奈。簡言之摆昧,它是在每個(gè)讀的數(shù)據(jù)行上加上共享鎖。在這個(gè)級(jí)別蜒程,可能導(dǎo)致大量的超時(shí)現(xiàn)象和鎖競爭绅你。
這幾行看了不知道多少次了,感覺理解總還是有問題昭躺,遂寫一下忌锯。
理解有障礙的在于Repeatable Read 級(jí)別所解決的問題以及幻讀的成因。這個(gè)級(jí)別解決了nonrepatable read的問題领炫。事務(wù)A執(zhí)行期間偶垮,事務(wù)B的修改操作將不會(huì)對(duì)A造成影響,因?yàn)樗麜?huì)保證在事務(wù)中多次讀取的同樣的記錄結(jié)果是一致的帝洪。
那幻讀是什么呢似舵? 幻讀是事務(wù)A期間,事務(wù)B insert了一些記錄葱峡,事務(wù)A在query一個(gè)范圍內(nèi)記錄的時(shí)候恰巧包含了剛插入的記錄砚哗,導(dǎo)致前后query的結(jié)果不一樣。
綜上砰奕,我理解的是可重復(fù)讀這個(gè)級(jí)別蛛芥,其他事務(wù)update操作不會(huì)對(duì)這個(gè)事務(wù)的query造成影響提鸟,但是insert或delete還是會(huì)有影響的。
另外仅淑,mysql默認(rèn)的是可重復(fù)讀的級(jí)別称勋,他解決幻讀的方式是MVCC。
innoDB的MVCC是通過在每行記錄后面保存兩個(gè)隱藏的列來實(shí)現(xiàn)的涯竟,這兩列赡鲜,一個(gè)保存了行的創(chuàng)建時(shí)間,一個(gè)保存了過期時(shí)間(此處時(shí)間不是真的時(shí)間庐船,而是版本號(hào))蝗蛙。每個(gè)事務(wù),版本號(hào)都會(huì)遞增醉鳖。下邊是可重復(fù)讀級(jí)別下的具體行為
SELECT
Innodb檢查每行數(shù)據(jù),確保他們符合兩個(gè)標(biāo)準(zhǔn):
1哮内、InnoDB只查找版本早于當(dāng)前事務(wù)版本的數(shù)據(jù)行(也就是數(shù)據(jù)行的版本必須小于等于事務(wù)的版本)盗棵,這確保當(dāng)前事務(wù)讀取的行都是事務(wù)之前已經(jīng)存在的,或者是由當(dāng)前事務(wù)創(chuàng)建或修改的行
2北发、行的刪除操作的版本一定是未定義的或者大于當(dāng)前事務(wù)的版本號(hào)纹因,確定了當(dāng)前事務(wù)開始之前,行沒有被刪除
符合了以上兩點(diǎn)則返回查詢結(jié)果琳拨。
INSERT
InnoDB為每個(gè)新增行記錄當(dāng)前系統(tǒng)版本號(hào)作為創(chuàng)建ID瞭恰。
DELETE
InnoDB為每個(gè)刪除行的記錄當(dāng)前系統(tǒng)版本號(hào)作為行的刪除ID。
UPDATE
InnoDB復(fù)制了一行狱庇。這個(gè)新行的版本號(hào)使用了系統(tǒng)版本號(hào)惊畏。它也把系統(tǒng)版本號(hào)作為了刪除行的版本。