隔離(數(shù)據(jù)庫(kù)系統(tǒng))
在數(shù)據(jù)庫(kù)系統(tǒng)中执隧,隔離決定了其他用戶和系統(tǒng)如何看到事務(wù)完整性。 例如户侥,當(dāng)用戶創(chuàng)建采購(gòu)訂單并創(chuàng)建了表頭但未創(chuàng)建采購(gòu)訂單行時(shí)镀琉,表頭對(duì)其他系統(tǒng)/用戶是否可見(jiàn)(執(zhí)行并行操作,如采購(gòu)訂單報(bào)告)蕊唐?
較低的隔離級(jí)別會(huì)增加許多用戶同時(shí)訪問(wèn)相同數(shù)據(jù)的能力屋摔,但會(huì)增加用戶可能遇到的并發(fā)影響(如臟讀或丟失更新)的數(shù)量。 相反替梨,更高的隔離級(jí)別減少了用戶可能遇到的并發(fā)影響的種類钓试,但需要更多的系統(tǒng)資源装黑,并增加了一個(gè)事務(wù)阻塞另一個(gè)事務(wù)的可能性。
隔離通常在數(shù)據(jù)庫(kù)級(jí)別定義為一個(gè)屬性弓熏,該屬性定義一個(gè)操作所做的更改如何/何時(shí)對(duì)其他操作可見(jiàn)恋谭。 在較舊的系統(tǒng)上,它可以通過(guò)系統(tǒng)實(shí)現(xiàn)挽鞠,例如通過(guò)使用臨時(shí)表箕别。 在兩層系統(tǒng)中,需要事務(wù)處理(TP)管理器來(lái)維護(hù)隔離滞谢。 在n層系統(tǒng)(例如試圖預(yù)訂航班最后一個(gè)座位的多個(gè)網(wǎng)站)中串稀,需要結(jié)合使用存儲(chǔ)過(guò)程和交易管理來(lái)完成預(yù)訂并向客戶發(fā)送確認(rèn)。
當(dāng)一個(gè)事務(wù)被允許從一個(gè)被另一個(gè)正在運(yùn)行的事務(wù)修改但尚未提交的行讀取數(shù)據(jù)時(shí)狮杨,發(fā)生臟讀(又名未提交依賴)母截。
隔離是ACID(Atomicity 原子性, Consistency 一致性, Isolation 隔離, Durability 耐久性)的屬性之一。
并發(fā)控制
并發(fā)控制包含DBMS中處理隔離并保證相關(guān)正確性的基本機(jī)制橄教。數(shù)據(jù)庫(kù)和存儲(chǔ)引擎(見(jiàn)上文)大量使用它來(lái)保證并發(fā)事務(wù)的正確執(zhí)行清寇,以及(不同的機(jī)制)其他DBMS進(jìn)程的正確性。與事務(wù)相關(guān)的機(jī)制通常根據(jù)數(shù)據(jù)庫(kù)數(shù)據(jù)訪問(wèn)操作時(shí)間(事務(wù)調(diào)度)將命令分類為以可串行性和可恢復(fù)性為特征的調(diào)度屬性护蝶。限制數(shù)據(jù)庫(kù)訪問(wèn)操作執(zhí)行通常意味著性能(執(zhí)行率)降低华烟,因此并發(fā)控制機(jī)制通常被設(shè)計(jì)為在約束下提供盡可能最佳的性能。通常持灰,如果可能的話盔夜,在不損害正確性的情況下,可串行性屬性會(huì)受到制約以獲得更好的性能堤魁。但是喂链,可恢復(fù)性不會(huì)受到制約,因?yàn)檫@通常會(huì)違反數(shù)據(jù)庫(kù)完整性約束妥泉。
兩階段鎖定是DBMS中最常見(jiàn)的事務(wù)并發(fā)控制方法椭微,用于為數(shù)據(jù)庫(kù)訪問(wèn)的正確性提供可串行性和可恢復(fù)性。為了訪問(wèn)數(shù)據(jù)庫(kù)對(duì)象盲链,事務(wù)首先需要獲取該對(duì)象的鎖贴彼。根據(jù)訪問(wèn)操作類型(例如讀取或?qū)懭雽?duì)象)和鎖定類型浊闪,如果另一個(gè)事務(wù)正在為該對(duì)象持有鎖定蓬蝶,則可能會(huì)阻止并推遲獲取該鎖定峭跳。
隔離級(jí)別
在DBMS(數(shù)據(jù)庫(kù)管理系統(tǒng))中的四個(gè)ACID屬性中,隔離屬性是最經(jīng)常放松的屬性悠轩。當(dāng)試圖保持最高級(jí)別的隔離時(shí)间狂,DBMS通常會(huì)獲取可能導(dǎo)致并發(fā)性丟失或?qū)崿F(xiàn)多版本并發(fā)控制的數(shù)據(jù)鎖定。這需要為應(yīng)用程序添加邏輯才能正常運(yùn)行火架。
大多數(shù)DBMS提供了許多事務(wù)隔離級(jí)別鉴象,它們控制選擇數(shù)據(jù)時(shí)發(fā)生的鎖定程度忙菠。對(duì)于許多數(shù)據(jù)庫(kù)應(yīng)用程序,可以構(gòu)造大多數(shù)數(shù)據(jù)庫(kù)事務(wù)以避免需要高隔離級(jí)別(例如SERIALIZABLE級(jí)別)纺弊,從而減少系統(tǒng)的鎖定開(kāi)銷牛欢。程序員必須仔細(xì)分析數(shù)據(jù)庫(kù)訪問(wèn)代碼,以確保放松隔離不會(huì)導(dǎo)致難以發(fā)現(xiàn)的軟件錯(cuò)誤淆游。相反傍睹,如果使用更高的隔離級(jí)別,則會(huì)增加死鎖的可能性犹菱,這也需要仔細(xì)分析和編程技術(shù)來(lái)避免拾稳。
Serializable
這是最高的隔離級(jí)別。
使用基于鎖的并發(fā)控制DBMS實(shí)現(xiàn)時(shí)腊脱,可序列化要求在事務(wù)結(jié)束時(shí)釋放讀取和寫入鎖(在選定數(shù)據(jù)上獲确玫谩)。當(dāng)SELECT查詢使用范圍WHERE子句時(shí)陕凹,還必須獲取范圍鎖悍抑,特別是為了避免幻像讀取現(xiàn)象。
使用基于非鎖定的并發(fā)控制時(shí)杜耙,不會(huì)獲取鎖定;但是搜骡,如果系統(tǒng)在幾個(gè)并發(fā)事務(wù)中檢測(cè)到寫沖突,則只允許其中一個(gè)事務(wù)提交佑女。有關(guān)此主題的更多詳細(xì)信息记靡,請(qǐng)參閱快照隔離
來(lái)自:(第二份非正式評(píng)審草案)ISO / IEC 9075:1992,數(shù)據(jù)庫(kù)語(yǔ)言SQL- 1992年7月30日:在隔離級(jí)別SERIALIZABLE下執(zhí)行并發(fā)SQL事務(wù)保證可序列化珊豹◆こ剩可序列化的執(zhí)行被定義為執(zhí)行并發(fā)執(zhí)行的SQL事務(wù)的操作榕订,這些操作產(chǎn)生與那些相同的SQL事務(wù)的一些串行執(zhí)行相同的效果店茶。串行執(zhí)行是每個(gè)SQL事務(wù)在下一個(gè)SQL事務(wù)開(kāi)始之前執(zhí)行完成的一次執(zhí)行。
Repeatable reads
在此隔離級(jí)別中劫恒,基于鎖的并發(fā)控制DBMS實(shí)現(xiàn)會(huì)保持讀取和寫入鎖定(在選定數(shù)據(jù)上獲确坊谩)直到事務(wù)結(jié)束。但是两嘴,范圍鎖不受管理丛楚,因此可能發(fā)生幻像讀取。
在這個(gè)隔離級(jí)別寫偏序是可能的憔辫,寫偏序——Write Skew趣些,是一種由于允許兩個(gè)不同的寫入器(先前讀取它們正在更新的列)寫入到同一表中的同一列,導(dǎo)致列的數(shù)據(jù)是這兩個(gè)事務(wù)的混合贰您。其根本的原因是由于每個(gè)事務(wù)在更新過(guò)程中無(wú)法看到其他事務(wù)的更改的結(jié)果坏平,導(dǎo)致各個(gè)事務(wù)提交之后的最終結(jié)果違反了一致性拢操。
Read committed
在這個(gè)隔離級(jí)別中,基于鎖的并發(fā)控制DBMS實(shí)現(xiàn)會(huì)保持寫鎖(在選定數(shù)據(jù)上獲炔疤妗)直到事務(wù)結(jié)束令境,但是只要SELECT操作被執(zhí)行,讀鎖就會(huì)被釋放(所以不可重復(fù)讀取現(xiàn)象可以發(fā)生在這個(gè)隔離級(jí)別)顾瞪。與前一級(jí)一樣舔庶,范圍鎖不受管理。
簡(jiǎn)單來(lái)說(shuō)陈醒,read committed是一個(gè)隔離級(jí)別惕橙,它保證讀取數(shù)據(jù)時(shí)讀取的任何數(shù)據(jù)都被提交。它只是限制讀者看到任何中間的钉跷,未提交的吕漂,“臟”的閱讀。它不會(huì)承諾如果事務(wù)重新發(fā)布讀取尘应,它會(huì)找到相同的數(shù)據(jù)惶凝;數(shù)據(jù)讀取后可以自由更改。
Read uncommitted
這是最低的隔離級(jí)別犬钢。在這個(gè)級(jí)別中苍鲜,允許臟讀,因此一個(gè)事務(wù)可能會(huì)看到其他事務(wù)未做出的更改玷犹。
由于每個(gè)隔離級(jí)別都比下面更強(qiáng)混滔,因?yàn)闆](méi)有更高的隔離級(jí)別允許較低級(jí)別禁止的操作,該標(biāo)準(zhǔn)允許DBMS以比所請(qǐng)求的更高的隔離級(jí)別運(yùn)行事務(wù)(例如歹颓,“讀取已提交”事務(wù)實(shí)際上可以在“可重復(fù)讀”隔離級(jí)別執(zhí)行)坯屿。
讀取現(xiàn)象
當(dāng)事務(wù)1讀取事務(wù)2可能已經(jīng)改變的數(shù)據(jù)時(shí),ANSI / ISO標(biāo)準(zhǔn)SQL 92引用三種不同的讀取現(xiàn)象巍扛。
臟讀
臟讀(又名未提交依賴)發(fā)生在當(dāng)事務(wù)允許從某行讀取數(shù)據(jù)领跛,但該行正在被其他事務(wù)修改并且未提交的時(shí)候。
臟讀的工作方式與不可重復(fù)讀取類似; 但是撤奸,第二個(gè)事務(wù)不需要為第一個(gè)查詢返回不同的結(jié)果吠昭。 READ UNCOMMITTED隔離級(jí)別中可能阻止的唯一事情是更新在結(jié)果中出現(xiàn)亂序; 也就是說(shuō),前面的更新將始終在后面更新之前出現(xiàn)在結(jié)果集中胧瓜。
在我們的示例中矢棚,事務(wù)2會(huì)更改一行,但不會(huì)提交更改府喳。 事務(wù)1然后讀取未提交的數(shù)據(jù)蒲肋。 現(xiàn)在,如果事務(wù)2回滾其更改(已由事務(wù)1讀取)或更新對(duì)數(shù)據(jù)庫(kù)的不同更改兜粘,則數(shù)據(jù)視圖在事務(wù)1的記錄中可能是錯(cuò)誤的强胰。
重現(xiàn)步驟:
1. 設(shè)置propagation="REQUIRED" isolation="READ_UNCOMMITTED";
2. 執(zhí)行查詢記錄1妹沙,Thread.sleep(3000)偶洋;
3. 在事務(wù)1休眠期間,執(zhí)行事務(wù)2更新記錄1距糖;
4. 再次執(zhí)行查詢記錄1玄窝;
5. 事務(wù)2拋出異常,發(fā)生回滾悍引;
兩次結(jié)果不一致恩脂,發(fā)生臟讀。若改為isolation="READ_COMMITTED"趣斤,兩次結(jié)果一致俩块。
不可重復(fù)的讀
發(fā)生不可重復(fù)讀取時(shí),在事務(wù)過(guò)程中浓领,行被檢索兩次玉凯,行之間的值在讀取之間不同。
當(dāng)執(zhí)行SELECT時(shí)未獲取讀取鎖定時(shí)联贩,或者在執(zhí)行SELECT操作時(shí)立即釋放獲取的受影響行上的鎖定時(shí)漫仆,基于鎖定的并發(fā)控制方法中可能出現(xiàn)不可重復(fù)讀取現(xiàn)象。 在多版本并發(fā)控制方法下泪幌,當(dāng)由提交沖突影響的事務(wù)必須回滾的要求放寬時(shí)盲厌,可能發(fā)生不可重復(fù)讀取。
重現(xiàn)步驟:
1. 設(shè)置propagation="REQUIRED" isolation="READ_COMMITTED"祸泪;
2. 執(zhí)行查詢記錄1吗浩,Thread.sleep(3000);
3. 在事務(wù)1休眠期間没隘,事務(wù)2更新記錄1并提交懂扼;
4. 再次執(zhí)行查詢記錄1;
兩次結(jié)果不一致升略,發(fā)生不可重復(fù)讀微王。若改為isolation="REPEATABLE_READ",結(jié)果一致品嚣。
幻讀
在事務(wù)處理過(guò)程中,當(dāng)另一個(gè)事務(wù)將新行添加到正在讀取的記錄時(shí)钧大,會(huì)發(fā)生幻像讀取翰撑。
在執(zhí)行SELECT ... WHERE操作時(shí)沒(méi)有獲取范圍鎖定時(shí)可能會(huì)發(fā)生這種情況。 當(dāng)事務(wù)1重復(fù)有范圍的SELECT ... WHERE查詢并且在兩個(gè)操作之間,事務(wù)2創(chuàng)建(即INSERT)滿足WHERE的新行(即眶诈,在目標(biāo)表中)時(shí)涨醋,幻像讀取異常是非重復(fù)讀取的特例。
重現(xiàn)步驟:
1. 設(shè)置propagation="REQUIRED" isolation="REPEATABLE_READ"逝撬;
2. 執(zhí)行查詢記錄10-30浴骂,Thread.sleep(3000);
3. 在事務(wù)1休眠期間宪潮,事務(wù)2更新記錄10-30并提交溯警;
4. 再次執(zhí)行查詢記錄10-30;
兩次結(jié)果一致狡相,沒(méi)有發(fā)生幻讀梯轻。有可能是一定幾率的。
為了重現(xiàn)幻讀尽棕,下面我又試了幾種配置:
注意:
數(shù)據(jù)庫(kù)要關(guān)閉一級(jí)緩存喳挑,不然同樣的查詢,執(zhí)行兩次滔悉,第二次拿到的會(huì)是緩存中的數(shù)據(jù)伊诵,可以在映射mapping中這樣配置:
參考:
https://en.wikipedia.org/wiki/Isolation_(database_systems)
寫偏序——Write Skew。根本的原因是由于每個(gè)事務(wù)在更新過(guò)程中無(wú)法看到其他事務(wù)的更改的結(jié)果回官,導(dǎo)致各個(gè)事務(wù)提交之后的最終結(jié)果違反了一致性日戈。