免费开放阅读 | 数据库管理系统的事务原理(上)
作者介紹: 那海藍(lán)藍(lán),騰訊技術(shù)工程事業(yè)群計(jì)費(fèi)平臺(tái)部金融云TDSQL數(shù)據(jù)庫(kù)T4級(jí)專家,熟悉PostgreSQL、MySQL、Informix等數(shù)據(jù)庫(kù)內(nèi)核技術(shù),著有《數(shù)據(jù)庫(kù)查詢優(yōu)化器的藝術(shù)》一書。《數(shù)據(jù)庫(kù)事務(wù)處理的藝術(shù)》為最新出版力作,經(jīng)機(jī)械工業(yè)出版社授權(quán),“騰訊技術(shù)工程官方號(hào)”將獨(dú)家免費(fèi)開放閱讀,我們將分期為讀者奉上那海藍(lán)藍(lán)的技術(shù)盛宴。
本篇介紹數(shù)據(jù)庫(kù)管理系統(tǒng)的事務(wù)處理技術(shù),從數(shù)據(jù)庫(kù)的事務(wù)理論出發(fā)界定事務(wù)處理技術(shù)的范圍,討論了事務(wù)機(jī)制應(yīng)對(duì)的問題、事務(wù)處理的理論基礎(chǔ)和并發(fā)控制技術(shù)。
全篇立足于數(shù)據(jù)庫(kù)事務(wù)處理的基本理論,第 1 章界定了本書討論的事務(wù)處理技術(shù)所解決的問題,幫助讀者理解事務(wù)處理技術(shù)的背景和需求。在筆者看來(lái),理解問題比掌握解決問題的方式更為重要。
第 2 章講述事務(wù)處理技術(shù)的基本概念和理論,但不是對(duì)經(jīng)典教科書的翻錄,而是結(jié)合筆者多年數(shù)據(jù)庫(kù)內(nèi)核開發(fā)的心得和經(jīng)驗(yàn),融入自己的理解,幫助讀者從眾多的頭緒中理出線索。當(dāng)然,要想徹底理解掌握事務(wù)處理的基礎(chǔ)理論,還需要系統(tǒng)、全面地閱讀經(jīng)典的事務(wù)處理教材。
如果能夠把閱讀經(jīng)典教材和本書相結(jié)合,并對(duì)比印證,則如步入百花叢中:百花叢中識(shí)花香,迷霧夢(mèng)里尋捷徑,這是一本好書所能做到的事情。
但愿書長(zhǎng)久,十年共嬋娟。
第 1 章?數(shù)據(jù)庫(kù)管理系統(tǒng)的事務(wù)原理
數(shù)據(jù)庫(kù)管理系統(tǒng)(DataBase? Management? System,DBMS,以下簡(jiǎn)稱“數(shù)據(jù)庫(kù)”),是位于用戶與操作系統(tǒng)之間的一層數(shù)據(jù)管理軟件,功能主要包括:數(shù)據(jù)定義、數(shù)據(jù)操縱、數(shù)據(jù)庫(kù)的運(yùn)行管理、數(shù)據(jù)庫(kù)的建立和維護(hù) 等 。
數(shù)據(jù)庫(kù)的事務(wù)處理機(jī)制,是數(shù)據(jù)庫(kù)技術(shù)的基石。掌握數(shù)據(jù)庫(kù)技術(shù),必須要掌握事務(wù)處理的技術(shù),這樣才能把握數(shù)據(jù)庫(kù)的核心技術(shù)。同時(shí),也必須了解數(shù)據(jù)庫(kù)為什么會(huì)需要事務(wù)處理技術(shù),即事務(wù)處理技術(shù)要解決的問題,這一點(diǎn),就是我們?cè)诘谝徽碌谝还?jié)開門見山地提出的問題。
?
1.1 事務(wù)模型要解決的問題
事務(wù)模型,是電子交易操作的保障。沒有事務(wù)模型,并發(fā)操作以及操作中途的系統(tǒng)異常將可能使數(shù)據(jù)發(fā)生混亂,本節(jié)就各種潛在的問題進(jìn)行討論。
1.1.1?????為什么需要事務(wù)處理機(jī)制
數(shù)據(jù)庫(kù)為什么需要事務(wù)處理機(jī)制?
面對(duì)這個(gè)問題,一些數(shù)據(jù)庫(kù)相關(guān)從業(yè)者掩卷思考,給出以下幾個(gè)答案:
答案一:數(shù)據(jù)庫(kù)的事務(wù)處理機(jī)制,主要是解決臟讀、不可重復(fù)讀、幻讀等問題的。答案二:數(shù)據(jù)庫(kù)的事務(wù)處理機(jī)制,主要是實(shí)現(xiàn)了ACID 特性的。
答案三:數(shù)據(jù)庫(kù)的事務(wù)處理機(jī)制,主要是以多版本兩階段封鎖協(xié)議實(shí)現(xiàn)可串行化快照隔離。引自《數(shù)據(jù)庫(kù)系統(tǒng)概論》王珊,薩師暄著。
?
以上答案,哪個(gè)正確呢?其實(shí),沒有一個(gè)是正確的。
對(duì)于第一個(gè)回答,提出了事務(wù)處理技術(shù)中可能出現(xiàn)的三種經(jīng)典問題,這三種問題,是數(shù)據(jù)庫(kù)事務(wù)處理技術(shù)中并發(fā)控制模塊為實(shí)現(xiàn)不同隔離級(jí)別而要解決的三個(gè)問題,不是事務(wù)處理機(jī)制面臨的問題。所以第一個(gè)回答,以局部問題來(lái)覆蓋整體,以偏概全了。
第二個(gè)回答,提出了 ACID四大特性 ,這四個(gè)特性在關(guān)系型數(shù)據(jù)庫(kù)中一個(gè)也不可少, 但這僅僅是“四個(gè)特性”,并不是我們需要數(shù)據(jù)庫(kù)事務(wù)處理機(jī)制的根本原因。
第三個(gè)回答,提出了多項(xiàng)事務(wù)處理機(jī)制中需要的技術(shù),如多版本(Multiversion concurrency control,MVCC)、兩階段封鎖(2 Phase Lock)、快照隔離(Snapshot Isolation)等,但是這些技術(shù)僅僅是事務(wù)處理機(jī)制中的一些重要技術(shù),用于并發(fā)控制管理和隔離級(jí)別的實(shí)現(xiàn),并不是需要事務(wù)處理機(jī)制的原因。
那么,什么是數(shù)據(jù)庫(kù)事務(wù)模型被提出的原因呢?
我們先回避問題,繞道看如下的一個(gè)實(shí)際用戶操作,從 A 賬戶轉(zhuǎn)賬 50 元到 B 賬戶,其過程如表1-1 所示。
表 1-1 事務(wù)處理機(jī)制的作用
第一種情況,沒有事務(wù)處理機(jī)制 | 第二種情況 ,有事務(wù)處理機(jī)制 |
1. read(A) 2. A := A – 50 3.? write(A) 4.? read(B) 5. B := B + 50 6. write(B) | ?begin 1. read(A) 2. A := A – 50 3.? write(A) 4.? read(B) 5. B := B + 50 6. write(B) ?commit |
假設(shè)第 3 行“3. write(A) ”操作完成,A 賬戶已經(jīng)少 了 50 元 | 假設(shè)第 3 行“3. write(A) ”操作完成,A 賬戶已經(jīng)少 了 50 元 |
從第四行開始,數(shù)據(jù)庫(kù)宕機(jī);重啟后,A 賬戶少了 50 元但是 B 賬戶卻沒有增加 50 元 | 從第四行開始,數(shù)據(jù)庫(kù)宕機(jī);重啟后,事務(wù)沒有提交, A 賬戶盡管少了 50 元,但是事務(wù)因沒有成功提交,導(dǎo)致 A 減少 50 元的操作“失效” |
那么,A 少了的 ?50 元,哪里去了? | 那么,A 少了 50 元的操作,被回滾掉了,A 不會(huì)有 經(jīng)濟(jì)損失 |
如果發(fā)生這樣的事情,誰(shuí)還敢用數(shù)據(jù)庫(kù)來(lái)記錄交易信息? | 如果發(fā)生這樣的事情,A 是不是不用擔(dān)心劃賬失敗了? |
事務(wù)處理機(jī)制,就是要保證用戶的數(shù)據(jù)操作動(dòng)作對(duì)數(shù)據(jù)是“安全的”。
那么,什么樣的操作是安全的呢?數(shù)據(jù)只有在帶有“ ACID ”四個(gè)特性的事務(wù)處理機(jī)制的保障下,才可以認(rèn)為是“安全的”。
這里提到的大家耳熟能詳?shù)摹?ACID”四個(gè)特性,正是事務(wù)模型的核心內(nèi)容。事務(wù)概念及其相關(guān)技術(shù)(為實(shí)現(xiàn)“ACID”四個(gè)特性的技術(shù))的提出,給應(yīng)用開發(fā)人員抽象出一個(gè)非常好用的數(shù)據(jù)處理模型,這個(gè)模型可以保證:操作間串行執(zhí)行,執(zhí)行中不必?fù)?dān)心出錯(cuò)。這
ACID,A是原子性,C是一致性,I是隔離性,D是持久性。詳見1.2.1節(jié)。
就是事務(wù)模型被提出的原因。A 保證了操作(一些有完整邏輯意義的數(shù)據(jù)讀寫動(dòng)作)要么成功要么失敗,A 和 C 保證了數(shù)據(jù)不會(huì)因?qū)懖僮靼l(fā)生不一致,I 保證了在多會(huì)話并發(fā)讀寫同一份數(shù)據(jù)的情況下數(shù)據(jù)的完全一致(或數(shù)據(jù)可能不一致但尚可接受),D 保證了被修改的數(shù)據(jù)能長(zhǎng)久地存儲(chǔ)。
事務(wù)模型自被提出后,逐漸成為商業(yè)世界穩(wěn)定有序運(yùn)作的基石,數(shù)據(jù)和數(shù)據(jù)承載的交易事件的結(jié)果不會(huì)因系統(tǒng)故障被損傷。關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng)實(shí)現(xiàn)了事務(wù)模型,使得數(shù)據(jù)庫(kù)在電子交易中發(fā)揮了非常重要的作用。這也是數(shù)據(jù)庫(kù)為什么需要事務(wù)處理機(jī)制,即事務(wù)模型的原因。
1.1.2 事務(wù)機(jī)制要處理的問題—事務(wù)故障、系統(tǒng)故障、介質(zhì)故障
事務(wù)模型是商業(yè)世界運(yùn)作的基石,主要體現(xiàn)在交易處理電子化。作為一個(gè)軟件系統(tǒng), 數(shù)據(jù)庫(kù)系統(tǒng)會(huì)遭遇一些故障,如我們常說(shuō)的事務(wù)故障、系統(tǒng)故障、介質(zhì)故障等。
對(duì)于數(shù)據(jù)庫(kù)系統(tǒng),因?yàn)閿?shù)據(jù)實(shí)在太為重要,數(shù)據(jù)庫(kù)系統(tǒng)應(yīng)該能夠保證在出現(xiàn)故障時(shí), 數(shù)據(jù)依然滿足 ACID 特性。
對(duì)于事務(wù)內(nèi)部的故障,一般可分為預(yù)期的和非預(yù)期的。預(yù)期的事務(wù)內(nèi)部故障是指可以通過數(shù)據(jù)庫(kù)的事務(wù)處理機(jī)制發(fā)現(xiàn)的事務(wù)內(nèi)部故障,這時(shí)數(shù)據(jù)庫(kù)的事務(wù)處理機(jī)制提供了回滾操作保證了數(shù)據(jù)免受損害;非預(yù)期的事務(wù)內(nèi)部故障如運(yùn)算溢出故障、并發(fā)事務(wù)死鎖故障、違反了某些完整性約束而導(dǎo)致的故障等,數(shù)據(jù)庫(kù)系統(tǒng)依然可以通過回滾操作保證數(shù)據(jù)免受損害,所以回滾操作在事務(wù)處理機(jī)制中占有重要地位,不同的數(shù)據(jù)系統(tǒng)對(duì)回滾的實(shí)現(xiàn)方式也不盡相同。
對(duì)于系統(tǒng)故障,如數(shù)據(jù)庫(kù)在運(yùn)行過程中,由于硬件故障、數(shù)據(jù)庫(kù)軟件及操作系統(tǒng)的漏洞、突然停電等,數(shù)據(jù)庫(kù)系統(tǒng)停止運(yùn)行,所有正在運(yùn)行的事務(wù)以非正常方式終止,需要數(shù)據(jù)庫(kù)系統(tǒng)重新啟動(dòng),這時(shí),數(shù)據(jù)庫(kù)系統(tǒng)為保障ACID 特性,提供了基于 REDO/UNDO 的恢復(fù)機(jī)制,可以正確恢復(fù)到系統(tǒng)崩潰前的狀態(tài)。
介質(zhì)故障也稱為硬故障,主要指數(shù)據(jù)庫(kù)在運(yùn)行過程中,由于磁頭碰撞、磁盤損壞、強(qiáng)磁干擾、天災(zāi)人禍等情況,使得數(shù)據(jù)庫(kù)中的數(shù)據(jù)部分或全部丟失。解決這一類故障,要依賴于備份系統(tǒng)和歸檔日志,歸檔的日志、系統(tǒng)運(yùn)行期間記載的REDO/UNDO 日志等日志相關(guān)內(nèi)容,也是事務(wù)處理機(jī)制的一部分,日志管理部分的內(nèi)容較多,一般的書籍會(huì)將日志管理獨(dú)立為若干章節(jié)進(jìn)行討論。
總的來(lái)說(shuō),事務(wù)處理機(jī)制為應(yīng)對(duì)這三類故障,提供了很多技術(shù),如日志與恢復(fù)子系統(tǒng)、并發(fā)控制子系統(tǒng)、存儲(chǔ)子系統(tǒng)等,和事務(wù)處理機(jī)制密切相關(guān),我們將在1.2 節(jié)繼續(xù)進(jìn)行討論。
1.1.3 并發(fā)帶來(lái)的問題—三種常見的讀數(shù)據(jù)異?,F(xiàn)象
數(shù)據(jù)不在 ACID 特性的保護(hù)下會(huì)發(fā)生不一致的現(xiàn)象,那么:在 ACID 的保護(hù)下,是不是數(shù)據(jù)就一定不會(huì)產(chǎn)生不一致的現(xiàn)象呢?
在關(guān)系數(shù)據(jù)庫(kù)系統(tǒng)中,多個(gè)會(huì)話(session)可以訪問同一個(gè)數(shù)據(jù)庫(kù)的同一個(gè)表的同一行數(shù)據(jù)。這樣,對(duì)于數(shù)據(jù)而言,就意味著在同一個(gè)時(shí)間段內(nèi),有多個(gè)會(huì)話可以對(duì)其施加操作(或讀操作或?qū)懖僮?#xff09;,讀寫操作施加的順序不同以及事務(wù)中 A 特性對(duì)事務(wù)結(jié)果的影響(或成功或失敗,即要么提交要么中止),這三種因素疊加在一起,會(huì)存在幾種對(duì)數(shù)據(jù)有不同影響的情況:
讀– 讀操作:如果同時(shí)只存在多個(gè)讀操作,對(duì)于數(shù)據(jù)自身則沒有影響;既讀和讀操作互不影響數(shù)據(jù)的一致性,讀讀操作可以并發(fā)執(zhí)行。
讀 – 寫操作:如果讀寫操作都存在,因?qū)懺谇白x在后(如臟讀現(xiàn)象)、讀在前寫在后
(如不可重復(fù)讀現(xiàn)象),或者讀在前寫在后然后又讀(如幻象現(xiàn)象),就可能因數(shù)據(jù)被寫而導(dǎo)致另外一個(gè)讀操作的會(huì)話讀到錯(cuò)誤的數(shù)據(jù)。這個(gè)操作可以根據(jù)動(dòng)作發(fā)生的先后順序被細(xì)分為讀 – 寫操作、寫 – 讀操作。
寫 – 寫操作:如果同時(shí)存在多個(gè)寫操作,寫 – 寫操作直接改變了數(shù)據(jù)在同一時(shí)刻的語(yǔ)義,這就更不被允許,所以寫 – 寫操作通常不允許被并發(fā)執(zhí)行。但是,如果不做并發(fā)控制,寫– 寫并發(fā)操作也會(huì)帶來(lái)數(shù)據(jù)異常現(xiàn)象(1.1.4節(jié)探討寫 – 寫操作引發(fā)的異常)。
這三種情況的第二種,對(duì)應(yīng)了 SQL 標(biāo)準(zhǔn)中定義的三種數(shù)據(jù)異常的現(xiàn)象,注意這三種異常都是針對(duì)某個(gè)事務(wù)(第 2.2.1 節(jié)稱這樣的事務(wù)為“主事務(wù)”)的讀操作而言的。SQL2003標(biāo)準(zhǔn)對(duì)于數(shù)據(jù)異?,F(xiàn)象的定義如下:
The isolation level specifies the kind of phenomena that can occur during the execution of concurrent SQL-transactions. The following phenomena are possible:
1) P1 (“Dirty read”): SQL-transaction T1 modifiesa row. SQL-transaction T2 then read sthat row before T1 performs a COMMIT. If T1 then performs a ROLLBACK, T2 will have read a row that was never committed and that may thus be considered to have never existed.
2) P2 (“Non-repeatable read”): SQL-transaction T1 readsa row. SQL-transaction T2 then modifies or deletes that row and performs a COMMIT. If T1 then attempts to reread the row, it may receive the modified valueor discover that the row has been deleted.
3) P3 (“Phantom”): SQL-transaction T1 reads the set of rows N that satisfy some <search condition>. SQL-transaction T2 then executes SQL-statements that generate one or more rows that satisfy the <search con-dition> used by SQL-transaction T1. If SQL-transaction T1 then repeats the initial read with the same <search condition>, it obtains a different collection of rows.
怎么理解上面的內(nèi)容呢?從 SQL 標(biāo)準(zhǔn)的定義可以看出:
?首先,涉及了并發(fā)事務(wù)(concurrentSQL-transactions):至少有兩個(gè)事務(wù)同時(shí)發(fā)生,如上面所舉的三種異?,F(xiàn)象中,分別使用了事務(wù)T1和 T2。但是,更為復(fù)雜的情況,如下一節(jié)所談到的“寫偏序(writeskew)”現(xiàn)象的發(fā)生可以是兩個(gè)或三個(gè)事務(wù)同時(shí)發(fā)生。
其次,涉及了隔離級(jí)別(isolation level):如果多個(gè)事務(wù)是“可串行化”的,則意味著事務(wù)之間不應(yīng)該互相影響(不是“一定互不影響”而是“不應(yīng)該互相影響”),即邏輯上不應(yīng)當(dāng)存在“讀寫”沖突,所以數(shù)據(jù)庫(kù)引擎實(shí)現(xiàn)時(shí)應(yīng)該避免“讀寫”沖突造成的數(shù)據(jù)不一致的現(xiàn)象。避免的含義就是在數(shù)據(jù)庫(kù)引擎編碼實(shí)現(xiàn)的時(shí)候,采取并發(fā)控制技術(shù),消除“臟讀”、“不可重復(fù)讀”、“幻象”這三種現(xiàn)象。采取的手段是分級(jí)控制(不同的隔離級(jí)別),分別使用“已提交? (READCOMMITTED)”、“可重復(fù)讀(REPEATABLE? READ)”和“可串行化(SERIALIZABLE)”這幾種隔離級(jí)別,來(lái)應(yīng)對(duì)這三種數(shù)據(jù)不一致的現(xiàn)象。
數(shù)據(jù)操作的對(duì)象,臟讀和不可重復(fù)讀是以“row”(一行)為單位,而幻象現(xiàn)象操作的是一個(gè)數(shù)據(jù)集(零行到多行)。
下面,我們把 SQL 標(biāo)準(zhǔn)的話語(yǔ)轉(zhuǎn)為一個(gè)表格(如表 1-2 所示),以更好地理解一下三種異?,F(xiàn)象。
表 1-2 SQL 標(biāo)準(zhǔn)定義的三種讀數(shù)據(jù)異?,F(xiàn)象
說(shuō)明:
表格頭兩行,表明? SQL? 標(biāo)準(zhǔn)定義的三種異?,F(xiàn)象,分別是臟讀、不可重復(fù)讀、幻象。
表格第一列,時(shí)間值列,表明時(shí)間值在逐漸增長(zhǎng),即 t0<t1<t2<t3。
對(duì)于每一種異常現(xiàn)象,都分為2個(gè)列,分別是兩個(gè)并發(fā)的事務(wù),各自命名為 T1事務(wù)和 T2事務(wù)。
表格中的 R(row),表示讀 row數(shù)據(jù)對(duì)象;W(row) 表示寫 row對(duì)象,讀寫操作的是同一個(gè)數(shù)據(jù)對(duì)象 row;W(row)-Update/Delete后面的 Update/Delete表示的寫操作是DML語(yǔ)句中的 UPDATE或 DELETE語(yǔ)句產(chǎn)生的寫數(shù)據(jù)庫(kù)對(duì)象 row的操作。
帶有“ R(rows)-WHERE<condition> ”的表示SQL語(yǔ)句讀數(shù)據(jù)(通常是 SELECT語(yǔ)句)帶有 WHERE子句,此子句的條件表達(dá)式是“<condition> ”。
帶有“ W(rows)-Update/Insert-<condition>”的表示寫操作生成的數(shù)據(jù)滿足與其他事務(wù)讀操作帶有的相同的條件表達(dá)式“<condition> ”,且此寫操作要么是UPDATE,要么是 INSERT語(yǔ)句。
帶有底色的,表示其對(duì)應(yīng)時(shí)刻,如果發(fā)生對(duì)應(yīng)的操作,將引發(fā)異?,F(xiàn)象。
臟讀現(xiàn)象:按照時(shí)間順序,T1事務(wù)在 t0時(shí)刻對(duì) row進(jìn)行了修改(更新),T2事務(wù)在 t1時(shí)刻先讀取了被 T1修改了的 row的值,但是 T1在 t2時(shí)刻中止使得對(duì)row的修改失效。如果數(shù)據(jù)庫(kù)引擎不支持因并發(fā)操作避免數(shù)據(jù)異常,則 T2在 t1 時(shí)刻讀到的就是 T1修改后的數(shù)據(jù),但是這個(gè)數(shù)據(jù)在現(xiàn)實(shí)世界中不存在,對(duì)于事務(wù) T2而言,讀取了被回滾掉的數(shù)據(jù),即事務(wù) T2發(fā)生了臟讀異?,F(xiàn)象。另外 , 對(duì)于臟讀現(xiàn)象 , 還存在如表 1-3的兩種變形情況。
不可重復(fù)讀現(xiàn)象:事務(wù) T1在 t0時(shí)刻先讀取 row的舊值,事務(wù) T2在 t1時(shí)刻對(duì) row進(jìn)行了修改(更新或刪除)然后提交事務(wù)使得修改生效,此時(shí)row因更新變?yōu)榱诵轮祷蛞騽h除而不再存在。接下來(lái),事務(wù) T1在 t3時(shí)刻再次讀取 row對(duì)象的值但是 row的值已經(jīng)是新值或者不存在了。對(duì)于事務(wù) T1 而言,物是(同樣是讀 row這個(gè)對(duì)象)人非(值已經(jīng)和 t0時(shí)刻讀到的值不同),事務(wù) T1發(fā)生了不可重復(fù)讀異?,F(xiàn)象。
幻象現(xiàn)象:事務(wù) T1在 t0時(shí)刻帶有特定條件地讀取了row對(duì)象的數(shù)據(jù),事務(wù) T2在 t1 時(shí)刻插入新的數(shù)據(jù)或更新其他舊數(shù)據(jù)但滿足事務(wù)T1的特定 WHERE 條件,新的數(shù)據(jù)滿足與事務(wù) T1同樣的條件,當(dāng)事務(wù) T1在t3時(shí)刻再次以同樣的條件讀取數(shù)據(jù)的時(shí)候,rows 對(duì)象的值已經(jīng)有新加入的行(因插入而比第一次讀多出了數(shù)據(jù))。對(duì)于事務(wù) T1而言,物是(同樣是讀滿足“<condition> ”條件的多個(gè) row對(duì)象)人非(值已經(jīng)和 t0時(shí)刻讀到的值不同),事務(wù) T1發(fā)生了幻象異?,F(xiàn)象?;孟笥址Q為幻讀,即第二次讀操作讀取了第一次讀操作沒有讀到的rows(一行或多行)。
臟讀異常的變形如表 1-3 所示。
表 1-3?? 臟讀異常的變形
在了解了 SQL 標(biāo)準(zhǔn)定義的三種異常現(xiàn)象后,回到我們?cè)诒竟?jié)開始提出的問題:
在 ACID 的保護(hù)下,是不是數(shù)據(jù)就一定不會(huì)產(chǎn)生不一致的現(xiàn)象呢?
答 案 已 經(jīng) 很 明確: 即 使 數(shù) 據(jù) 庫(kù) 系 統(tǒng) 提 供 ACID, 除 非 我 們 使 用“可 串 行 化
(SERIALIZABLE)”隔離級(jí)別,否則數(shù)據(jù)在其他不同的隔離級(jí)別下還會(huì)產(chǎn)生數(shù)據(jù)不一致的現(xiàn)象。
有關(guān)這三種數(shù)據(jù)異常現(xiàn)象的更多探討,請(qǐng)參見 1.1.7 節(jié)。
1.1.4 并發(fā)帶來(lái)的問題—寫 – 寫并發(fā)操作引發(fā)的數(shù)據(jù)異?,F(xiàn)象
上一節(jié),我們探討了三種讀數(shù)據(jù)異?,F(xiàn)象,請(qǐng)注意,異?,F(xiàn)象發(fā)生在一個(gè)事務(wù)中后面的READ 讀操作上。這三種讀數(shù)據(jù)異常現(xiàn)象被 SQL 標(biāo)準(zhǔn)定義。那么:是不是對(duì)數(shù)據(jù)的并發(fā)操作只會(huì)產(chǎn)生上述的三種讀數(shù)據(jù)異?,F(xiàn)象?
事務(wù)概念的奠基人,Jim Grey 先生,在其著作《事務(wù)處理:概念與技術(shù)》中提到了一個(gè)“Lost Update ”異常的概念,字面含義是“更新丟失”,這是一個(gè)寫操作的異常,與上一節(jié)提到的三種讀操作異常不同。
除了“ Lost Update ”異常外,這一節(jié)我們還將探討另外一種異常,如表 1-4所示。
表 1-4?? 寫數(shù)據(jù)異?,F(xiàn)象
說(shuō)明:
表格頭兩行,表明寫寫并發(fā)操作引發(fā)的兩種異?,F(xiàn)象,分別是臟寫、丟失更新。
表格第一列,時(shí)間值列,表明時(shí)間值在逐漸增長(zhǎng),即 t0<t1<t2<t3。
對(duì)于每一種異?,F(xiàn)象,都分為2個(gè)列,分別是兩個(gè)并發(fā)的事務(wù),各自命名為 T1事務(wù)和 T2事務(wù)。
表格中的 R(row),表示讀 row數(shù)據(jù)對(duì)象;W(row) 表示寫 row對(duì)象,讀寫操作的是同一個(gè)數(shù)據(jù)對(duì)象 row;W(row)-Update后面的 Update表示的寫操作是 DML語(yǔ)句中的UPDATE語(yǔ)句產(chǎn)生的寫數(shù)據(jù)庫(kù)對(duì)象 row的操作。
帶有陰影背景的,表示其對(duì)應(yīng)時(shí)刻,如果發(fā)生對(duì)應(yīng)的操作,將引發(fā)異常現(xiàn)象。
臟寫現(xiàn)象:按照時(shí)間順序,事務(wù) T1在 t0時(shí)刻對(duì) row進(jìn)行了修改(更新),事務(wù) T2在 t1時(shí)刻對(duì) row進(jìn)行了修改(更新),如果沒有并發(fā)控制,T2對(duì) row的修改會(huì)生成新值,但是 T1在 t3時(shí)刻回滾使得 T2對(duì) row的修改失效,而 T1的語(yǔ)義是:T1 自身對(duì) row的修改失效,這就把 T2修改的值回滾掉。對(duì)于事務(wù) T1而言,回滾掉了不是自己修改的數(shù)據(jù),即事務(wù) T1上發(fā)生了臟寫現(xiàn)象。
丟失更新現(xiàn)象:按照時(shí)間順序,事務(wù) T2在 t1時(shí)刻對(duì) row進(jìn)行了修改(更新),事務(wù)
T1在 t2時(shí)刻對(duì) row進(jìn)行了修改(更新),如果沒有并發(fā)控制,T1對(duì) row的修改會(huì)生成新值,但是 T1在 t3時(shí)刻提交使得 T2對(duì) row的修改失效。對(duì)于事務(wù) T1而言,覆蓋掉了不是自己修改的數(shù)據(jù),即事務(wù) T1上引發(fā)了丟失更新現(xiàn)象(t3時(shí)刻如果是事務(wù)
T2提交而不是事務(wù)T1提交,也是丟失更新,只是事務(wù)T2上引發(fā)了丟失更新現(xiàn)象)。不管是讀異常還是寫異常,并發(fā)控制技術(shù)都要規(guī)避這些異常,保證數(shù)據(jù)在不同隔離級(jí)別下一致性不被破壞。
1.1.5 語(yǔ)義約束引發(fā)的數(shù)據(jù)異常現(xiàn)象
如果說(shuō)數(shù)據(jù)在 ACID 特性(帶有了并發(fā)控制技術(shù))的保護(hù)下會(huì)發(fā)生不一致的現(xiàn)象,那么:在 ACID 和快照隔離級(jí)別技術(shù)(多版本)的保護(hù)下,是不是數(shù)據(jù)就一定不再會(huì)產(chǎn)生不一致的現(xiàn)象呢?
答案是否定的。數(shù)據(jù)庫(kù)系統(tǒng)中數(shù)據(jù)的異常,在多種并發(fā)控制技術(shù)中已經(jīng)被解決,但這不表明所有的異常都已經(jīng)被解決,更不表明不再有新的異常被發(fā)現(xiàn)。
我們知道,數(shù)據(jù)庫(kù)并發(fā)控制技術(shù)中有一個(gè)大名鼎鼎的技術(shù),稱為快照隔離(Snapshot Isolation) ,這項(xiàng)技術(shù)解決了讀和寫之間的沖突,在保證數(shù)據(jù)不會(huì)產(chǎn)生前面兩節(jié)提到的讀異常和寫異常的情況下,使得讀寫互不阻塞(兩階段封鎖技術(shù)中讀寫操作互相阻塞),提高了并發(fā)度。
注意我們這里談到的多版本是“multi-version,簡(jiǎn)稱 MV ”,其相對(duì)于“single-valued,簡(jiǎn)稱 SV”,這個(gè)多版本是指并發(fā)控制技術(shù)中的數(shù)據(jù)項(xiàng)有多個(gè)版本,其含義僅此而已??煺崭綦x并發(fā)技術(shù)是多版本并發(fā)控制(Multiversion concurrency control,MVCC)技術(shù)的一部分, 其發(fā)生作用,需基于“數(shù)據(jù)項(xiàng)存在多個(gè)版本”。
快照隔離并發(fā)控制技術(shù)的缺點(diǎn),是并不能真正保證事務(wù)為“可串行化的”,即事務(wù)間的并發(fā)操作依舊會(huì)引發(fā)數(shù)據(jù)異?,F(xiàn)象,但是這里的數(shù)據(jù)異?,F(xiàn)象有別于前面提到的各種異?,F(xiàn)象,其異常現(xiàn)象是“業(yè)務(wù)的邏輯語(yǔ)義”引發(fā)的,即除了抽象的讀寫操作,數(shù)據(jù)間還應(yīng)該滿足一定語(yǔ)義,即約束(constraint)。
在快照隔離并發(fā)控制技術(shù)中并發(fā)的事務(wù)因不滿足約束而發(fā)生的異常,稱為“寫偏序(Write Skew)”,這樣的異常有兩種,參見表 1-5。
說(shuō)明:
表格頭兩行,表明寫偏序異?,F(xiàn)象的兩種情況,分別是由兩個(gè)事務(wù)引發(fā)異常、三個(gè)事務(wù)引發(fā)異常。
表格第一列,時(shí)間值列,表明時(shí)間值在逐漸增長(zhǎng),即 t0<t1<t2<t3<t4<t5<t6<t7。
對(duì)于每一種異常現(xiàn)象,都分為2個(gè)列,分別是兩個(gè)并發(fā)的事務(wù),各自命名為 T1事務(wù)和 T2事務(wù)。
? ?詳情參見2.1.2節(jié)。
表 1-5 寫偏序異常的兩種情況
二個(gè)事務(wù)引發(fā)的異?,F(xiàn)象(簡(jiǎn)單寫偏序,Simple Write Skew):按照時(shí)間順序,T1 事務(wù)在t0時(shí)刻讀取了在打電話的值班醫(yī)生個(gè)數(shù),T2事務(wù)在 t1時(shí)刻也讀取了在打電話的值班醫(yī)生個(gè)數(shù)。事務(wù) T1在 t2時(shí)刻進(jìn)行判斷:如果在打電話的值班醫(yī)生個(gè)數(shù)大于等于2?人則請(qǐng)Alice停止打電話。事務(wù) T2在 t3時(shí)刻進(jìn)行判斷:如果在打電話的值班醫(yī)生個(gè)數(shù)大于等于 2人則請(qǐng) Bob停止打電話。然后事務(wù) T1和 T2分別提交。如果在這種并發(fā)的情況下,允許事務(wù)T1和 T2都提交成功,則 t6時(shí)刻,Alice和 Bob都停止了打電話。如果串行執(zhí)行事務(wù),先執(zhí)行事務(wù) T1后執(zhí)行事務(wù) T2,Alice會(huì)停止打電話但 Bob不會(huì)停止,這與前一種情況的結(jié)果不同;如果先執(zhí)行事務(wù) T2后執(zhí)行事務(wù) T1,Bob會(huì)停止打電話但 Alice不會(huì)停止,這與前一種情況的結(jié)果也不同;這表明前一種并發(fā)執(zhí)行是非序列化的,而此時(shí),事務(wù) T1、T2并發(fā)時(shí)違反了約束(約束為:如果同時(shí)打電話的人數(shù)大于等于2人則請(qǐng) Alice或 Bob其中一個(gè)人停止打電話直到同時(shí)打電話的人數(shù)少于 2人) 發(fā)生了寫偏序異?,F(xiàn)象。對(duì)于簡(jiǎn)單寫偏序,可以用一個(gè)形象化的圖表示,如圖 1-1 所示。
圖 1-1 兩個(gè)事務(wù)引發(fā)的異常現(xiàn)象優(yōu)先圖
? ?示例源自論文:DanR.K. Ports,KevinGrittner,SerializableSnapshotIsolationinPostgreSQL
三個(gè)事務(wù)引發(fā)的異?,F(xiàn)象(Batch Processing):對(duì)于這種情況,后兩個(gè)并發(fā)更新事務(wù)T3 和 T2 是可串行化的且不存在任何異常,但是一個(gè)只讀事務(wù) T1 出現(xiàn)在某個(gè)時(shí)刻卻可能正好造成問題。所出現(xiàn)的問題是這樣的,當(dāng)事務(wù) T3 提交時(shí),T2 處于活躍狀態(tài), 這時(shí),事務(wù) T1 啟動(dòng)要讀取事務(wù) T2 和 T3 涉及的數(shù)據(jù)(current_batch 和 receipts),這時(shí),事務(wù) T1 的快照包括了事務(wù)T3 的插入后的結(jié)果(因?yàn)?T3 已經(jīng)提交);但是,事務(wù) T2 沒有提交,它的插入操作數(shù)據(jù)不包含在事務(wù) T1 的快照中。在優(yōu)先圖(如圖 1-2 所示)中會(huì)造成一個(gè)環(huán)(有關(guān)如何形成這樣的環(huán),參見 2.2.5 節(jié)),說(shuō)明這樣的調(diào)度是非可串行化的。
圖 1-2 三個(gè)事務(wù)引發(fā)的異?,F(xiàn)象優(yōu)先圖
本節(jié)所述的這兩種情況,如果使用優(yōu)先圖表示,都可以在參與操作的事務(wù)之間,畫出一個(gè)環(huán),存在環(huán)說(shuō)明:調(diào)度是非可串行化的。為解決這樣的問題,要求數(shù)據(jù)庫(kù)引擎必須在事務(wù)提交時(shí)(甚至是環(huán)一形成即立刻回滾其中的一個(gè)事務(wù))而不是在快照上檢查完整性約束,以避免本節(jié)所述的不一致現(xiàn)象。
1.1.6其他的異常
在《A Critique of ANSI SQL Isolation Levels》這篇論文中,除了上面提到的幾種異?,F(xiàn)象外,還提到了另外兩種異常,如表 1-6 和表 1-7 所示。
表 1-6? 讀 偏 序
? ?圖1-1、圖1-2的具體含義,請(qǐng)參見2.2.5節(jié)。?
說(shuō)明:
表格頭兩行,表明讀偏序異?,F(xiàn)象,是由兩個(gè)事務(wù)引發(fā)異常。
表格第一列,時(shí)間值列,表明時(shí)間值在逐漸增長(zhǎng),即 t0<t1<t2<t3。
對(duì)于讀偏序異常現(xiàn)象,都分為2個(gè)列,分別是兩個(gè)并發(fā)的事務(wù),各自命名為 T1事務(wù)和 T2事務(wù)。
事務(wù) T1在 t0時(shí)刻讀出數(shù)據(jù) x,事務(wù) T2在 t1時(shí)刻對(duì)數(shù)據(jù) x和 y進(jìn)行了修改在 t2時(shí)刻提交,事務(wù) T1在 t3時(shí)刻讀取 y,y是被事務(wù) T2修改后的數(shù)據(jù),此時(shí)已經(jīng)不是 t0 時(shí)刻事務(wù) T1讀取 x時(shí)對(duì)應(yīng)的 y值,數(shù)據(jù)形成了不一致狀態(tài)(注意此時(shí)不是數(shù)據(jù)x處于不一致,而是 y處于不一致)。
游標(biāo)(Cursor),是數(shù)據(jù)庫(kù)引擎提供的一種讀取數(shù)據(jù)的方式。在數(shù)據(jù)庫(kù)中,為了防止使用游標(biāo)時(shí)其他事務(wù)并發(fā)修改游標(biāo)所包括的數(shù)據(jù),定義了游標(biāo)穩(wěn)定性(Cursor Stability)隔離級(jí)別,這樣的隔離級(jí)別,是在讀取當(dāng)前數(shù)據(jù)項(xiàng)的時(shí)刻,在數(shù)據(jù)項(xiàng)上加鎖,當(dāng)游標(biāo)從當(dāng)前數(shù)據(jù)項(xiàng)移走則解鎖,此后曾經(jīng)被讀取過的數(shù)據(jù)項(xiàng)不再被并發(fā)保護(hù)(盡管使用游標(biāo)的事務(wù)沒有提交或中止,還處于活動(dòng)狀態(tài))。但是,在使用游標(biāo)的時(shí)候,也會(huì)發(fā)生寫 – 寫異常,如表 1-7所示。
表 1-7?? 游標(biāo)丟失更新
說(shuō)明:
表格頭兩行,表明寫 – 寫并發(fā)操作引發(fā)的異?,F(xiàn)象,游標(biāo)丟失更新。
表格第一列,時(shí)間值列,表明時(shí)間值在逐漸增長(zhǎng),即 t0<t1<t2<t3。
對(duì)于每一種異常現(xiàn)象,都分為2個(gè)列,分別是兩個(gè)并發(fā)的事務(wù),各自命名為 T1事務(wù)和 T2事務(wù)。
游標(biāo)丟失更新現(xiàn)象:按照時(shí)間順序,事務(wù) T1在 t0時(shí)刻讀取 row的值后,即釋放了
row 上的鎖使得 row 沒有被并發(fā)保護(hù),事務(wù) T2 在 t1 時(shí)刻對(duì) row 進(jìn)行了修改(更新),事務(wù) T1 在 t2 時(shí)刻對(duì) row 進(jìn)行了修改(更新),如果沒有并發(fā)控制,T1 對(duì) row 的修改會(huì)生成新值,但是T1 在 t4 時(shí)刻提交使得 T2 對(duì) row 的修改失效。對(duì)于事務(wù) T1 而言, 覆蓋掉了不是自己修改的數(shù)據(jù),即事務(wù) T1 上引發(fā)了丟失更新現(xiàn)象。這樣的現(xiàn)象,本質(zhì)上就是丟失更新,只是發(fā)生在了游標(biāo)上,所以稱為游標(biāo)丟失更新。
我們?cè)?1.1.3 至 1.1.6 節(jié),介紹了各種因并發(fā)引發(fā)的異常現(xiàn)象,有多種技術(shù)(2.2 節(jié)介紹多種并發(fā)控制技術(shù))可以解決這些異?,F(xiàn)象,如下我們借用《A Critique of ANSI SQL Isolation Levels》這篇論文中的一張表,來(lái)簡(jiǎn)單總結(jié)一下前面幾節(jié)所談到的各種異常,如表1-8?所示。與隔離級(jí)別相關(guān)的內(nèi)容,參見 2.1節(jié)。
表1-8 所有的異常和隔離級(jí)別的關(guān)系
說(shuō)明:
P0 DirtyWrite:臟寫,1.1.4節(jié)表 1-3。
P1 DirtyRead:臟讀,1.1.3節(jié)表 1-2。
P4 CCursorLostUpdate:游標(biāo)丟失更新,1.1.6節(jié)表 1-6。
P4 LostUpdate:丟失更新,1.1.3節(jié)表 1-2。
P2 FuzzyRead:模糊讀,即不一致讀,1.1.3節(jié)表 1-2。
P3 Phantom:幻象,即幻讀,1.1.3節(jié)表 1-2。
A5A ReadSkew:讀偏序,1.1.6節(jié)表 1-5。
A5B WriteSkew:寫偏序,1.1.5節(jié)表 1-4。
與隔離級(jí)別相關(guān)的內(nèi)容,參見 2.1節(jié)。
深入探討三種讀數(shù)據(jù)異?,F(xiàn)象
在 1.1.3 節(jié),我們提出了并發(fā)帶來(lái)的三種異?,F(xiàn)象,分別是臟讀、不可重復(fù)讀、幻象, 其中幻象又被稱為“幻讀”。
這一節(jié),我們將以問答的形式,深入探討與這三種異?,F(xiàn)象相關(guān)的六個(gè)問題。
Q1:異?,F(xiàn)象是發(fā)生在表 1-2 中的事務(wù) T1 還是事務(wù) T2 ?
換一個(gè)提問方式,我們都知道數(shù)據(jù)庫(kù)提供了四種隔離級(jí)別,那么當(dāng)三種異常發(fā)生的時(shí)候,是應(yīng)該在事務(wù)T1 中還是事務(wù) T2 中設(shè)置隔離級(jí)別以避免數(shù)據(jù)異常現(xiàn)象的產(chǎn)生?
答:首先,需要區(qū)分操作發(fā)生的主體。數(shù)據(jù)庫(kù)啟動(dòng)多個(gè)會(huì)話,要想會(huì)話之間互不影響,則需要標(biāo)識(shí)哪個(gè)是當(dāng)前會(huì)話、哪個(gè)是其他會(huì)話,然后設(shè)置隔離級(jí)別。有人認(rèn)為,這個(gè)很簡(jiǎn)單,每個(gè)會(huì)話對(duì)于其自身就是當(dāng)前會(huì)話。但是,對(duì)于數(shù)據(jù)庫(kù)引擎而言,他是不知道哪個(gè)會(huì)話是當(dāng)前的會(huì)話。
其次,需要考慮并發(fā)度。對(duì)于數(shù)據(jù)庫(kù)引擎而言,如果因?yàn)閿?shù)據(jù)庫(kù)引擎不知道哪個(gè)會(huì)話是當(dāng)前的會(huì)話,所以給每個(gè)會(huì)話的事務(wù)都設(shè)置不同的隔離級(jí)別,減少各個(gè)會(huì)話的事務(wù)互相影響,則會(huì)降低并發(fā)度。
所以,在數(shù)據(jù)庫(kù)保留一個(gè)默認(rèn)的隔離級(jí)別(通常是較低的隔離級(jí)別以提高并發(fā)度)給每個(gè)會(huì)話的事務(wù)后,如果需要高的隔離級(jí)別,就需要在自己的事務(wù)中設(shè)置想要的隔離級(jí)別,以使得本事務(wù)不受其他事務(wù)的影響。因此,在數(shù)據(jù)庫(kù)系統(tǒng)中,我們要想使得事務(wù) T1不受其他事務(wù)的影響,則需要在事務(wù) T1內(nèi)部設(shè)置隔離級(jí)別,使得本事務(wù) T1不受其他并發(fā)事務(wù)對(duì)事務(wù) T1要讀寫的數(shù)據(jù)造成影響。換句話說(shuō),就是使得本事務(wù)不發(fā)生異常現(xiàn)象?;乜幢?-2 以及對(duì)表 1-2的說(shuō)明,我們可以看到如下內(nèi)容:
臟讀現(xiàn)象:……事務(wù) T2發(fā)生了臟讀異?,F(xiàn)象。
不可重復(fù)讀現(xiàn)象:……事務(wù) T1發(fā)生了不可重復(fù)讀異常現(xiàn)象。
幻象現(xiàn)象:……事務(wù) T1發(fā)生了幻象異?,F(xiàn)象。
這個(gè)結(jié)論看起來(lái)有點(diǎn)兒不“美”,即有點(diǎn)不協(xié)調(diào),臟讀是發(fā)生在了事務(wù) T2,不可重復(fù)讀和幻象是發(fā)生在了事務(wù)T1。
如果數(shù)據(jù)異常都發(fā)生在事務(wù) T1,則我們可以把事務(wù)T1 想象成為“本事務(wù)”,事務(wù) T2是其他并發(fā)的事務(wù),而我們當(dāng)前可以操作的(即有權(quán)限可以設(shè)置隔離級(jí)別)只能是“本事務(wù)”,其他并發(fā)發(fā)生的事務(wù)也許是其他權(quán)限用戶建立的會(huì)話,我們根本沒有權(quán)限操作即沒有權(quán)限去設(shè)置他人的隔離級(jí)別。
所以,數(shù)據(jù)異?,F(xiàn)象,一定是發(fā)生在本事務(wù)當(dāng)中的。我們統(tǒng)一以事務(wù) T1 為本事務(wù)(也稱為“主事務(wù)”),觀察本事務(wù)和其他并發(fā)事務(wù)之間因讀寫操作的先后次序不同而造成的不同的數(shù)據(jù)異常。因此,我們修正表 1-2 的內(nèi)容如表1-9 所示。
表 1-9 修正后的SQL 標(biāo)準(zhǔn)定義的三種讀數(shù)據(jù)異?,F(xiàn)象
? “W(rows)-Update/Insert? =><condition>”表示更新和插入操作的行滿足“<condition>”。
對(duì)于 Q1 問題的回答,依據(jù)表 1-9,數(shù)據(jù)異常現(xiàn)象發(fā)生在表 1-9 中的主事務(wù) T1 中。其實(shí),如上修改是為了明確并發(fā)事務(wù)的數(shù)據(jù)異常現(xiàn)象發(fā)生在哪里。即研究別的事務(wù)對(duì)于本事務(wù)的影響,而不是討論本事務(wù)對(duì)別的事務(wù)的影響。
對(duì)于數(shù)據(jù)庫(kù)引擎的編碼實(shí)現(xiàn),就是在一個(gè)會(huì)話中考慮本會(huì)話(主事務(wù)對(duì)應(yīng)的會(huì)話)因不同的隔離級(jí)別(在主事務(wù)中設(shè)置的隔離級(jí)別)在發(fā)生沖突后而產(chǎn)生什么樣的動(dòng)作(可繼續(xù)執(zhí)行本事務(wù)內(nèi)的后續(xù) SQL 還是直接回滾掉本事務(wù))。所以,請(qǐng)注意,動(dòng)作發(fā)生的主體,一定是主事務(wù)。而且,異常是發(fā)生在主事務(wù)的讀操作這樣的動(dòng)作上(指三種讀異常)。
Q2 :從表 1-9 中看,對(duì)于臟讀現(xiàn)象,寫操作是事務(wù)T2 執(zhí)行 UPDATE 引發(fā)的,那么, 事務(wù) T2 的寫操作可以是刪除(DELETE)或插入(INSERT)嗎?
答:臟讀,強(qiáng)調(diào)的是主事務(wù)讀取了一個(gè)不存在(因回滾而不存在)的數(shù)據(jù)。
如果事務(wù) T2的寫操作是刪除操作,在 row這行數(shù)據(jù)被刪除后,事務(wù) T1不可能在后面的時(shí)間點(diǎn) t1上讀到同一個(gè) row(SQL標(biāo)準(zhǔn)中特意強(qiáng)調(diào)了“thatrow”,參見 1.1.3節(jié));因此臟讀現(xiàn)象中“事務(wù) T1一定可以讀到同一個(gè) row”是不能滿足的,因此,臟讀中的事務(wù)T2 的寫操作不可能是刪除。
如果事務(wù) T2 的寫操作是插入操作,在row 這行數(shù)據(jù)被插入后,事務(wù) T1 能在后面的時(shí)間點(diǎn)上讀到同一個(gè) row(SQL 標(biāo)準(zhǔn)中特意強(qiáng)調(diào)了“ that? row ”);因此臟讀現(xiàn)象中事務(wù) T1 一定可以讀到同一個(gè) row 的條件是被滿足的,因此,臟讀中的事務(wù)T2 的寫操作可以是插入。
Q3:對(duì)于不可重復(fù)讀現(xiàn)象,事務(wù) T2 的寫操作是否可以是插入操作?
答:對(duì)于事務(wù) T2 的 W(row) 操作,row 是一個(gè)已經(jīng)存在的行,這表明是在一個(gè)存在的特定對(duì)象上進(jìn)行的操作,所以不可能是插入操作。
Q4:不可重復(fù)讀和幻象有什么區(qū)別?
答:首先,這兩種異常,對(duì)于主事務(wù) T1 而言,都是先讀取了數(shù)據(jù),之后因事務(wù) T2“寫” 了數(shù)據(jù)而事務(wù) T1 再次讀取數(shù)據(jù)的時(shí)候,發(fā)生了異常。但是,如表1-9 所示,不可重復(fù)讀對(duì)于事務(wù) T1 讀取的是一個(gè)存在的確定的一行數(shù)據(jù)(意味著這行數(shù)據(jù)是存在的數(shù)據(jù)),這個(gè)行數(shù)據(jù)本身被事務(wù) T2 使用更新或刪除操作而改變;而幻象對(duì)于事務(wù) T1 讀取的是滿足條件“ <condition> ”的多行數(shù)據(jù)(意味著“<condition> ”是一個(gè)范圍查找,結(jié)果集不確定),所以從第一次讀取數(shù)據(jù)的操作的角度看,前者是讀取特定的多行,后者讀取的是多行但可能 不確定。不過,對(duì)于所讀的數(shù)據(jù)而言,由此可以產(chǎn)生一個(gè)新的問題,參見Q5。其次,這兩種異常,對(duì)于事務(wù) T2 而言,都是“寫”數(shù)據(jù),但是寫操作的具體動(dòng)作不同。如表 1-9 所示,不可重復(fù)讀對(duì)于事務(wù) T2 的寫操作是更新或刪除操作,而幻象對(duì)于事務(wù) T2 的寫操作是插入(插入的新數(shù)據(jù)滿足條件)或更新(使不滿足條件的數(shù)據(jù)在更新后滿足條件)操作。
第三,不可重復(fù)讀和幻象最大的區(qū)別就是前者只需要“鎖住”(考慮)已經(jīng)讀過的數(shù)據(jù),而幻象需要對(duì)“還不存在的數(shù)據(jù)”做出預(yù)防。
Q5:對(duì)于幻象現(xiàn)象,事務(wù) T2 的寫操作是否可以是更新操作或者刪除操作?
答:對(duì)于幻象現(xiàn)象中事務(wù) T2 的 W(rows) 操作,如果操作是一個(gè)更新或刪除操作,則表明這樣的操作等同于(相似但不完全一樣,區(qū)別參見 Q6)不可重復(fù)讀(即是在多個(gè)行數(shù)據(jù)上進(jìn)行更新或刪除,即在多個(gè)行數(shù)據(jù)上批量化重演了不可重復(fù)讀現(xiàn)象)。
如表 1-10 所示,比較不可重復(fù)讀和幻象現(xiàn)象。如果我們認(rèn)為幻象現(xiàn)象中的事務(wù)T2 可以是更新或刪除操作,則幻象就等同于不可重復(fù)讀。實(shí)際上,幻象是不可重復(fù)讀的一個(gè)特例,對(duì)于不可重復(fù)讀現(xiàn)象,可以擴(kuò)展其“ R(row)/W(row) ”的概念為“ R(rows)/W(rows) ” 即讀寫多行(實(shí)則是擴(kuò)展 1.1.3 節(jié) SQL 標(biāo)準(zhǔn)提出的不可重復(fù)讀的定義),即對(duì)多行的不可重復(fù)讀。只是 ANSI SQL 標(biāo)準(zhǔn)著眼于在單行上定義不可重復(fù)讀,本節(jié)擴(kuò)展的定義著眼于在多行上重復(fù)單行上定義的不可重復(fù)讀(而編碼實(shí)現(xiàn)的實(shí)踐中,數(shù)據(jù)庫(kù)引擎是對(duì)多行數(shù)據(jù)使用相同的方式進(jìn)行處理的)。
表 1-10 幻象的寫操作改為更新則等同于不可重復(fù)讀
另外,幻象異?,F(xiàn)象中的操作都帶有“<condition> ”,而不可重復(fù)讀現(xiàn)象中則沒有“<condition> ”, 這 可 以 把 不 可 重 復(fù) 讀 變 形 為 類 似“R(rows)-WHERE<true> ”, 即 “ <condition> ”相當(dāng)于“ <true> ”。但是, 幻象的定義, 強(qiáng)調(diào)的是在特定的行(元組) 被操作后,又有新的行被其他事務(wù)操作而產(chǎn)生,所以,我們可以重新校正表 1-9得到新的表1-11,發(fā)生變化的內(nèi)容使用深色背景表示,幻象現(xiàn)象中事務(wù)T2的操作是插入或更新。
從表 1-11 可以看出,不可重復(fù)讀現(xiàn)象中事務(wù) T2 著眼于對(duì)現(xiàn)有數(shù)據(jù)進(jìn)行操作;而幻象現(xiàn)象中事務(wù)T2 著眼于對(duì)新增(或不在鎖定范圍內(nèi)已經(jīng)存在的數(shù)據(jù)上做更新 / 插入后而得的數(shù)據(jù)滿足了謂詞條件)數(shù)據(jù)。這其實(shí)正是Q4 的答案。
Q6:表 1-11中,不可重復(fù)讀現(xiàn)象中的事務(wù) T2在 t2時(shí)刻執(zhí)行“ Commit”或不執(zhí)行“Commit”會(huì)有什么差別嗎?或者對(duì)于幻象現(xiàn)象,事務(wù)T2在 t2時(shí)刻沒有執(zhí)行“Commit”,這一點(diǎn)與不可重復(fù)讀有差別嗎?
答:對(duì)于這個(gè)問題,我們暫時(shí)不做回答,請(qǐng)讀者先行思考。在我們討論了并發(fā)控制相關(guān)的多種技術(shù)后,我們?cè)?2.2.6 節(jié)再深入探討這個(gè)問題。
表 1-11 第二次修正后的 SQL 標(biāo)準(zhǔn)定義的三種讀數(shù)據(jù)異常現(xiàn)象
總結(jié)
以上是生活随笔為你收集整理的免费开放阅读 | 数据库管理系统的事务原理(上)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 央视-腾讯发布报告:九成受访者认为AI
- 下一篇: 腾讯发布2017年代码报告