資料庫事務原子性、一致性是怎樣實現的?

資料庫事務原子性、一致性的實現機制是什麼?


這個問題的有趣之處,不在於問題本身(「原子性、一致性的實現機制是什麼」),而在於回答者的分歧反映出來的另外一個問題:原子性和一致性之間的關係是什麼?

我特別關注了@我練功發自真心
的答案,他正確地指出了,為了保證事務操作的原子性,必須實現基於日誌的REDO/UNDO機制。但這個答案仍然是不完整的,因為原子性並不能夠完全保證一致性

按照我個人的理解,在事務處理的ACID屬性中,一致性是最基本的屬性,其它的三個屬性都為了保證一致性而存在的。

首先回顧一下一致性的定義。所謂一致性,指的是數據處於一種有意義的狀態,這種狀態是語義上的而不是語法上的。最常見的例子是轉帳。例如從帳戶A轉一筆錢到帳戶B上,如果帳戶A上的錢減少了,而帳戶B上的錢卻沒有增加,那麼我們認為此時數據處於不一致的狀態。

在資料庫實現的場景中,一致性可以分為資料庫外部的一致性和資料庫內部的一致性。前者由外部應用的編碼來保證,即某個應用在執行轉帳的資料庫操作時,必須在同一個事務內部調用對帳戶A和帳戶B的操作。如果在這個層次出現錯誤,這不是資料庫本身能夠解決的,也不屬於我們需要討論的範圍。後者由資料庫來保證,即在同一個事務內部的一組操作必須全部執行成功(或者全部失敗)。這就是事務處理的原子性。

為了實現原子性,需要通過日誌:將所有對數據的更新操作都寫入日誌,如果一個事務中的一部分操作已經成功,但以後的操作,由於斷電/系統崩潰/其它的軟硬體錯誤而無法繼續,則通過回溯日誌,將已經執行成功的操作撤銷,從而達到「全部操作失敗」的目的。最常見的場景是,資料庫系統崩潰後重啟,此時資料庫處於不一致的狀態,必須先執行一個crash
recovery的過程:讀取日誌進行REDO(重演將所有已經執行成功但尚未寫入到磁碟的操作,保證持久性),再對所有到崩潰時尚未成功提交的事務進行UNDO(撤銷所有執行了一部分但尚未提交的操作,保證原子性)。crash
recovery結束後,資料庫恢復到一致性狀態,可以繼續被使用。

日誌的管理和重演是資料庫實現中最複雜的部分之一。如果涉及到並行處理和分散式系統(日誌的複製和重演是資料庫高可用性的基礎),會比上述場景還要複雜得多。

但是,原子性並不能完全保證一致性。在多個事務並行進行的情況下,即使保證了每一個事務的原子性,仍然可能導致數據不一致的結果。例如,事務1需要將100元轉入帳號A:先讀取帳號A的值,然後在這個值上加上100。但是,在這兩個操作之間,另一個事務2修改了帳號A的值,為它增加了100元。那麼最後的結果應該是A增加了200元。但事實上,
事務1最終完成後,帳號A只增加了100元,因為事務2的修改結果被事務1覆蓋掉了。

為了保證並發情況下的一致性,引入了隔離性,即保證每一個事務能夠看到的數據總是一致的,就好象其它並發事務並不存在一樣。用術語來說,就是多個事務並發執行後的狀態,和它們串列執行後的狀態是等價的。怎樣實現隔離性,已經有很多人回答過了,原則上無非是兩種類型的鎖:

一種是悲觀鎖,即當前事務將所有涉及操作的對象加鎖,操作完成後釋放給其它對象使用。為了儘可能提高性能,發明了各種粒度(資料庫級/表級/行級……)/各種性質(共享鎖/排他鎖/共享意向鎖/排他意向鎖/共享排他意向鎖……)的鎖。為了解決死鎖問題,又發明了兩階段鎖協議/死鎖檢測等一系列的技術。


一種是樂觀鎖,即不同的事務可以同時看到同一對象(一般是數據行)的不同歷史版本。如果有兩個事務同時修改了同一數據行,那麼在較晚的事務提交時進行衝突檢測。實現也有兩種,一種是通過日誌UNDO的方式來獲取數據行的歷史版本,一種是簡單地在內存中保存同一數據行的多個歷史版本,通過時間戳來區分。

鎖也是資料庫實現中最複雜的部分之一。同樣,如果涉及到分散式系統(分散式鎖和兩階段提交是分散式事務的基礎),會比上述場景還要複雜得多。

@我練功發自真心
提到,其他回答者說的其實是操作系統對atomic的理解,即並發控制。我不能完全同意這一點。資料庫有自己的並發控制和鎖問題,雖然在原理上和操作系統中的概念非常類似,但是並不是同一個層次上的東西。資料庫中的鎖,在粒度/類型/實現方式上和操作系統中的鎖都完全不同。操作系統中的鎖,在資料庫實現中稱為latch(一般譯為閂)。其他回答者回答的其實是「在並行事務處理的情況下怎樣保證數據的一致性」。

最後回到原來的問題(「原子性、一致性的實現機制是什麼」)。我手頭有本Database
System
Concepts(4ed,有點老了),在第15章的開頭簡明地介紹了ACID的概念及其關係。如果你想從概念上了解其實現,把這本書的相關章節讀完應該能大概明白。如果你想從實踐上了解其實現,可以找innodb這樣的開源引擎的源代碼來讀。不過,即使是一個非常粗糙的開源實現(不考慮太複雜的並行處理,不考慮分散式系統,不考慮針對操作系統和硬體的優化之類),要基本搞明白恐怕也不是一兩年的事。


先借用前輩的一句話:資料庫事務有不同的隔離級別,不同的隔離級別對鎖的使用是不同的,鎖的應用最終導致不同事務的隔離級別。

隔離性分為四個級別:

1讀未提交:(Read Uncommitted)

2讀已提交(Read Committed) 大多數資料庫默認的隔離級別

3可重複讀(Repeatable-Read) mysql資料庫所默認的級別

4序列化(serializable)

四個級別的具體實現和不同的請下面細讀:

首先程序是可以並發執行的,同樣,在MySQL中,一個表可以由兩個或多個進程同時來讀寫數據,這是沒有問題的。

比如,此時有兩個進程來讀數據,這也沒什麼問題,允許。但是如果一個進程在讀某一行的數據的過程中,另一個在進程又往這一行裡面寫數據(改、刪),那結果會是如何?同樣,如果兩個進程都同時對某一行數據進行更改,以誰的更改為準?那結果又會怎樣,不敢想像,是不是數據就被破壞掉了。所以此時是衝突的。

既然會衝突就要想辦法解決,靠誰來解決,這時候就是靠鎖機制來維護了。怎麼使用鎖來使他們不衝突?

在事務開始的時候可以給要準備寫操作的這一行數據加一個排它鎖,如果是讀操作,就給該行數據一個讀鎖。這樣之後,在修改該行數據的時候,不讓其他進程對該行數據有任何操作。而讀該行數據的時候,其他進程不能更改,但可以讀。讀或寫完成時,釋放鎖,最後commit提交。這時候讀寫就分離開了,寫和寫也就分離開了。

注意:此時加鎖和釋放鎖的過程由mysql資料庫自身來維護,不需要我們人為干涉。mysql開發者給這個解決衝突的方案起了一個名字叫做:讀未提交:(Read Uncommitted)。這也就是事務的第一個隔離性。

但是這個程度的隔離性僅僅是不夠的。看下面的測試結果:

1)A修改事務級別為:未提交讀。並開始事務,對user表做一次查詢

2)B事務更新一條記錄

3)此時B事務還未提交,A在事務內做一次查詢,發現查詢結果已經改變

4)B進行事務回滾

5)A再做一次查詢,查詢結果又變回去了

由試驗得知:在一個進程的事務當中,我更改了其中的一行數據,但是我修改完之後就釋放了鎖,這時候另一個進程讀取了該數據,此時先前的事務是還未提交的,直到我回滾了數據,另一個進程讀的數據就變成了無用的或者是錯誤的數據。我們通常把這種數據叫做臟數據,這種情況讀出來的數據叫做賍讀。

怎麼辦?依然是靠鎖機制。無非是鎖的位置不同而已,之前是只要操作完該數據就立馬釋放掉鎖,現在是把釋放鎖的位置調整到事務提交之後,此時在事務提交前,其他進程是無法對該行數據進行讀取的,包括任何操作。那麼資料庫為此種狀態的資料庫操作規則又給了一個名字叫做:讀已提交(Read Committed),或者也可以叫不可重複讀。這也就是事務的第二個隔離性。

在某些情況下,不可重複讀並不是問題,比如我們多次查詢某個數據當然以最後查詢得到的結果為主。但在另一些情況下就有可能發生問題,例如對於同一個數據A和B依次查詢就可能不同,A和B就可能打起來了……

繼續看下面的測試結果:

1)把隔離性調為READ-COMMITTED(讀取提交內容)設置A的事務隔離級別,並進入事務做一次查詢

2)B開始事務,並對記錄進行修改

3)A再對user表進行查詢,發現記錄沒有受到影響

4)B提交事務

5)A再對user表查詢,發現記錄被修改

試驗進行到這裡,你會發現,在同一個事務中如果兩次讀取相同的數據時,最後的結果卻不一致。這裡我們把這種現象稱為:不可重複讀。因為在第一個事務讀取了數據之後,此時另一個事務把該數據給修改了,這時候事務提交,那麼另一個事務在第二次讀取的時候,結果就不一樣,一個修改前的,一個是修改後的。

但是細心的你會發現,既然你說此種隔離性是在事務提交後才釋放鎖,那麼在試驗過程中,在該數據未提交前,另一個事務為什麼也是仍然可以讀取的呀。是我說錯了嗎?不是的,在這裡mysql使用了一個並發版本控制機制,他們把它叫做MVCC,通俗的也就是說:mysql為了提高系統的並發量,在事務未提交前,雖然事務內操作的數據是鎖定狀態,但是另一個事務仍然可以讀取,大多數資料庫默認的就是這個級別的隔離性。但mysql不是。

而且不只是在更新數據時出現這個問題,在插入數據時仍然會造成類似的這樣一種現象:mysql雖然鎖住了正在操作的數據行,但它仍然不會阻止另一個事務往表插入新行新的數據。比如:一個事務讀取或更新了表裡的所有行,接者又有另一個事務往該表裡插入一個新行,在事務提交後。原來讀取或更改過數據的事務又第二次讀取了相同的數據,這時候這個事務中兩次讀取的結果集行數就不一樣。原來更新了所有行,而現在讀出來發現竟然還有一行沒有更新。這就是所謂的幻讀。

為了防止同事務中兩次讀取數據不一致,(包括不可重讀和幻讀),接下來該如何繼續做呢?!

mysql依然採取的是MVCC並發版本控制來解決這個問題。具體是:如果事務中存在多次讀取同樣的數據,MySQL第一次讀的時候仍然會保持選擇讀最新提交事務的數據,當第一次之後,之後再讀時,mysql會取第一次讀取的數據作為結果。這樣就保證了同一個事務多次讀取數據時數據的一致性。這時候,mysql把這種解決方案叫做:可重複度(Repeatable-Read),也就是上述所寫的第三個隔離性,也是mysql默認的隔離級別。

注意:幻讀和不可重複讀(Read Committed)都是讀取了另一條已經提交的事務(這點就臟讀不同),所不同的是不可重複讀查詢的都是同一個數據項,而幻讀針對的是一批數據整體(比如數據的個數)。

說到這裡,真的就完事了嗎?到這裡其實mysql並未完全解決數據的一致性問題。只是在讀取上做了手腳,解決了傳統意義上的幻讀和不可重複讀。

例子:1 A事務開啟,B事務開啟。

2 B事務往表裡面插入了一條數據,但還並未提交。

3 A事務開始查詢了,並沒有發現B事務這次插入的數據。然後此時B事務提交了數據。

4 於是乎,A事務就以為沒有這條數據,就開始添加這條數據,但是卻發現,發生了數據 重複衝突。

最後這個時候,該我們的最後一種隔離級別也是最高的隔離級:別序列化(serializable)登場了。

該隔離級別會自動在鎖住你要操作的整個表的數據,如果另一個進程事務想要操作表裡的任何數據就需要等待獲得鎖的進程操作完成釋放鎖。可避免臟讀、不可重複讀、幻讀的發生。當然性能會下降很多,會導致很多的進程相互排隊競爭鎖。

後記:以上所說的四種隔離性的鎖機制應用是資料庫自動完成的,不需要人為干預。隔離級別的設置只對當前鏈接有效。對於使用MySQL命令窗口而言,一個窗口就相當於一個鏈接,當前窗口設置的隔離級別只對當前窗口中的事務有效

本文會繼續更新,後面會探討死鎖,已經我們該如何對鎖技術的應用該進行選型!

待繼續更新。。。。。


Locking and Row Versioning

看完所有子節點的字。


原子性:一個事務內的所有SQL操作是一個整體。都執行成功才算整個事務成功。如果某個失敗,則必須要會退到事務執行之前的狀態,執行成功的SQL需要被撤銷。

innodb通過undo log和redo log來實現。

事務中,每當執行一條SQL語句對數據產生了影響,就會記錄下來與之相反的操作到undo log(撤銷日誌)中,例如,更新會記錄之前的狀態,刪除會形成insert,添加會形成delete,一旦事務被回滾,則執行undo log中記錄的操作,來完成恢復到之前的狀態。這裡是個 邏輯恢復哦!

同時,每當執行一條事務中的SQL,會將操作記錄到redo log中,此時事務一旦被提交,就將該redolog中的操作,持久化到磁碟上,數據就持久的記錄下來了(ACID的D)。

PS:還有,undolog才是原子性的關鍵。提供redolog,應該主要目的是提升磁碟的IO開銷吧,如果直接寫入磁碟,IO開銷,會很大。如果先將操作記錄到redolog中,可以順序的記錄,批量的記錄,再一起同步到磁碟上,速度會比直接寫磁碟快些。 mysql在生成redolog時,會使用 innodb log buffer,先緩衝到內存中,再同步到redolog上。速度會更快

另外關於,一致性,應該是個整體概念,保證所有的mysql對象(數據,索引,約束,日誌,用戶)在事務執行前後都具有完整的特性,應該是mysql所有的功能都為此服務吧!

一家之言,歡迎拍磚!


嘗試簡單回答下

討論資料庫的事務原子性,先看最極端的情況,即全局一把鎖,所有事務排隊執行,這種情況下沒有原子性問題,因為所有事務看到的都是在自己之前已經提交的數據。

為了提高性能,充分利用多核,我們需要讓多個事務能夠並行的執行,但是還要保證這些事務「看起來」是串列執行的(external consistency)。這裡需要考慮事務的三種關係,即讀與讀的關係,寫與寫的關係,讀與寫的關係。

  1. 讀事務與讀事務的關係最簡單,因為不對數據進行修改,因此讀與讀之間可以直接並行

  2. 寫事務與寫事務的關係,對同一條記錄的修改,需要保證串列,不能出現lost update的情況,一般通過行鎖(oracle/mysql/oceanbase),或者事先通過SQL分析將可能衝突的事務排隊後執行(calvin/oceanbase)

  3. 讀事務與寫事務的關係,這個最複雜,因為資料庫操作中,幾乎沒有隻寫的情況,一般都是「read-modify-write」,比如最簡單的update ... where 還有 update set c=c+1 whete,絕大部分寫事務都是在讀取一些數據之後,再修改數據,我們稱這類事務為「讀寫事務」。因此讀與寫關係,會涉及兩類關係:

    1. 只讀事務與讀寫事務的關係,一般使用多版本的方式保存數據,每個事務分配一個全局唯一且遞增的「事務版本號」,更新數據時將事務版本號也保存在數據中。在全局維護一個「最大已提交的」版本號(committed version),一般就是一個64或128位的整數,每個只讀事務開始時,原子的讀取這個commited version,讀取數據時,只讀取版本號小於等於它的內容。多版本的實現方式各家不盡相同;數據存儲方面oracle與innodb都是使用data block + undo block的方式,歷史版本保存在undo block中,oceanbase內存引擎則簡單的將一行所有的修改歷史串成反向鏈表;對於事務版本號,oracle與oceanbase都在事務提交時生成版本號,可以保證版本號的大小嚴格遵守事務提交順序,但是需要在事務提交時(oceanbase)或提交後(oracle)將事務版本號回填到數據內容中,mysql則簡單的在事務開啟時生成版本號,因此讀取邏輯相對複雜,需要過濾掉開始事務時尚未結束事務對數據的修改。
    2. 讀寫事務之間的關係,這裡需要考慮的是一個讀寫事務T1在執行過程中,它剛剛讀過的數據被其他事務修改的情況,這種情況下T1需要回滾重做(單語句事務)或報告事務衝突(交互型事務),一般的做法是在T1提交時對涉及到的行加鎖後檢查版本號或內容,在read committed隔離級別下這個特性並非標準所要求,但是oracle/mysql/oceanbase都在語句級別實現了,也成為了事實標準,按oracle的叫法叫做transaction set consistency

參考文獻:

[1] Thomson A, Diamond T, Weng S C, et al. Calvin: fast distributed transactions for partitioned database systems[C]//Proceedings of the 2012 ACM SIGMOD International Conference on Management of Data. ACM, 2012: 1-12. MLA

[2] Berenson H, Bernstein P, Gray J, et al. A critique of ANSI SQL isolation levels[C]//ACM SIGMOD Record. ACM, 1995, 24(2): 1-10.

[3] LI Kai,HAN Fu-Sheng. Memory transaction engine of OceanBase[J]. Journal of East China Normal University(Natural Sc, 2014, 2014(5): 147-163.

[4] Lewis J. Oracle Core: Essential Internals for DBAs and Developers[M]. Apress, 2011.


首先說對原子性的理解。資料庫的理解和操作系統的理解是截然相反的。

資料庫的原子性說的其實不是樓上說的那些。資料庫的原子性說的是failure atomicity:一個事物要麼運行成功,要麼完全沒有運行。也正如題主所問的(非常貼切!),這東西和一致性直接相關。因為如果一個事務的修改到一半終止掉,那麼是不可能保持一致性的!

那麼樓上說的是啥呢?樓上說的其實是操作系統對atomic的理解:並發控制。OK為啥這麼說,因為操作系統直到現在都沒有一個統一的並發控制體系,最常用的並發控制就是:鎖。而且,鎖在操作系統里是沒法和數據進行對應的。所以,在操作系統里,用鎖來控制運行的順序:任何要看到非atomic的操作或者非consistent的線程和Interrupt handler都被鎖鎖在外面。所以,這是操作系統理解的一致性和原子性。

那麼資料庫說的一致性和原子性是怎麼實現的呢?

一般來說用journaling。

任何的修改都先寫在一個journal/log里。當事務提交時,會再寫一個叫做commit record的東西。那麼想像如下情況:如果斷電發生,沒有提交的事務完成了一半,這個事務就不會有commit record,那麼在恢復的時候就會跳過這個事務,就當它沒發生;如果提交的事務完成了,那麼你一定會看到一個commit record,這時候你就可以根據journal里的數據來恢復你資料庫的內容了,這時候,這個事務完整提交。

還有一個叫做copy on write/shadow paging的方法,一般不在資料庫中用。因為資料庫往往希望對連續讀做優化。(但誰知道以後呢…)

PS 資料庫的並發控制非常統一(isolation),樓上說了用鎖做控制是比較傳統的做法(2PL)。除此之外,還有著名的MVCC,比較激進的OCC方法等等…


Transactional Information Systems

這本書不錯,你也可以下到pdf版


其實底層就是鎖鎖鎖而已。只不過資料庫做了優化後,鎖的運用會顯得比較風騷。


簡單的說,可以依靠undo log,也有叫rollback log的,在寫資料庫的實際位置前,先把要寫的部分備份到undo log里,然後再寫實際位置。實際數據寫下去後,清除undo log。 如果在transaction中間機器crash了,資料庫會先讀undo log, 如果undolog裡面有內容,說明是在事務寫了一半的時候crash的,只要把undo log裡面的備份數據覆蓋會實際位置就行了。

參考這個:

https://www.sqlite.org/atomiccommit.html

另一種方式是redo log, 現在用的更廣泛。更容易順序話磁碟的io,就是把要寫的內容全寫寫到redolog裡面,然後再刷到實際位置,如果在事務中間crash了,恢復的時候直接把redo log的內容寫到硬碟中

也有redo log和undo log都用的情況。

參考資料庫實現的書吧

https://www.amazon.cn/gp/aw/d/B002Z13XJW/ref=ya_aw_oh_pii?ie=UTF8psc=1


事務的原子性,是事務的基本概念,沒法介紹,基本上也不會有人問.就好比1+1=2還值得討論,但是什麼是1,是沒有辦法描述的.

事務的一致性,是要和事務的隔離性一起來看的

首先,為了保證數據的一致性,mysql資料庫存在鎖機制.

1.讀鎖(又稱為共享鎖,s鎖)

事務A對某一條數據s1進行讀取時,加了讀鎖,其他事務只能讀取數據s1,只有當事務A釋放讀鎖後,才能對數據s1進行操作

2.寫鎖(又稱為排他鎖,x鎖)

事務A對某一條數據s1進行修改是,加了寫鎖,其他事務在A釋放寫鎖之前,不能讀取和修改數據s1

3.表單鎖

事務A對錶單設置表單鎖後,其他事務在A釋放表單鎖之前,不能對錶單進行操作

其次,mysql為了可以實現並發,提高效率,開發了mvcc

4. 並發多版本控制mvcc. 不同的並發訪問相應的當前版本(最新commit的版本)

將鎖機制/mvcc機制/事務隔離級別 結合起來看

a)read uncommitted :讀未提交 操作完數據立刻釋放鎖 (讀鎖/寫鎖) ,但是讀取到可能是提交之前的數據. 什麼問題都解決不了.

b)read committed:讀已提交 在commit提交之後,再釋放鎖(所以會出現提交後,不可重複讀和幻讀的現象) 可以實現當前操作的數據底層的一致性(有寫鎖存在,其他事務不能對數據進行查詢和修改),但是讀取數據時,可能會出現問題.

c)repeatable read :可重複讀 (本質上鎖機制和讀已提交一致,也就是可以實現當前操作數據底層的一致性)

1. mysql利用mvcc系統,當事務A和事務B同時存在時,當事務A對資料庫某條數據進行修改時(未commit提交),雖然該條數據存在寫鎖,但因為mvcc存在,事務B可以讀取當前版本-S1的資料庫信息.

2. 但是當事務B也對該條數據進行修改時,因為寫鎖存在,不能對數據進行修改.只有當事務A提交後,才能對數據進行操作(當事務A提交後,事務B會自動提交,但是修改語句不會執行,會報錯)

3. 事務B可以對資料庫的表進行增刪操作

4.事務都提交後(只查詢,對數據沒有影響),最後高版本資料庫覆蓋低版本

d)serializable :串列化 事務強制排序,使用表單鎖. 事務執行完成後,釋放表單鎖,下個事務才能對錶單進行操作.

也就是說,事務一致性,是由鎖機制實現的. 而事務的隔離性,是讀取數據時體現的.


ACID是不同資料庫對象齊心合力使資料庫管理系統呈現出的特點,它們之間沒有直接聯繫。說一致性由隔離性,原子性來保證,或者因為隔離性與原子性組合產生了一致性,不準確。

在允許偷幀和非強制寫的前提下,顯著保證以下特性的資料庫對象或演算法包括但不限於:

持久性: redo日誌,ARIES演算法 (不一定需要undo日誌),double write

(運行時)一致性: 讀寫鎖 (本質上是如何利用各種鎖和讀寫操作來正確規劃一個事務)

原子性: redo日誌,ARIES演算法

隔離性:多粒度鎖,讀寫鎖

舉個例子,不正確使用讀寫鎖,就可能出現臟讀,它符合一個隔離級別,但是破壞了更高隔離級別下的一致性。換句話說,DBA允許臟讀,那麼在這個DBA的眼中,這種數據不一致是可以容忍的,那麼就可以說數據是一致的。資料庫事務執行前後的一致性是由人來判斷的。

沒有了redo日誌,原子性被破壞。一個事務沒有被原子地完成,就說明事務沒有提交,本來查一下redo日誌就可以回滾,但因為沒有日誌,*此時*一致性被破壞了。

總之,從表面來看"特性"之間有相互影響的關係,但這不是一種真正有意義的關係。打個比方,人說的能力和寫的能力之間沒什麼有意義的聯繫,而是說的機能和寫的機能之間有聯繫。很多答主的意見不一事實上來源於此。

另: 閂鎖什麼的是給資料庫自己用的。當一個資料庫告訴你它用了行級鎖的時候不代表它沒用表級的閂。可以說閂鎖間接保證了上面所有特性,但沒什麼意義。

樂觀鎖悲觀鎖mvcc都屬於鎖性能優化的範疇而已。


就是事務設計的對象都上鎖,我搞完了你們才准動,就是自私


很精彩


不玩概念,具體而言,"一致性"這個就是東西就是 共享內存是不是需要複製的問題。 不考慮太複雜的情況,以共享內存為基礎,如果我們直接把一個文件映射到內存,然後直接操作映射的內存空間,這時,我們不知道內存與磁碟在什麼時候會有同步操作。那麼這時「一致性」的要求就無法達到了。但如果我們把原始數據作為參數,新產生的數據不寫到共享內存的存儲區,而是在一個複製出的內存空間寫新數據,在確定完成後,再回寫到共享內存。 雖然理論而言,仍然可能有不一致的情況,但這種情況的概率比第一種低了無數個量級,這時我們就可以說已經滿足了「一致性」要求。

而原子性就可以簡單理解為共享內存的 讀寫共享標記。 原子操作就是獲得寫許可權。


原子性對應ACID的A,一致性對應ACID的C。ACID一般來講是作為一個整體來保證的。保證ACID有很多種方式。比如一種悲觀鎖的方式可以使用strong strict two-phase locking和ARIES logging等技術。


需要看你的事務隔離級別,基本實現手段是鎖機制


每種資料庫可能實現起來略微不同,建議閱讀官方文檔,」絕對「有相關說明


事務處理


資料庫事務原子性、一致性的實現其實說的是並發機制的相關內容,解決的辦法是加鎖機制。

資料庫原理或者系統概述有專門的章節。

解決的辦法:

解決的辦法;

解決辦法;


認真回答肯定是一本書的量,我了解過MySQL的實現,原子性: (對索引)上鎖(此處涉及到事務隔離級別) , 一致性: (UNDO和REDO)日誌, 什麼提交段,回滾段balabala, 總之讓事情變得有據可尋之後一致性就好說了,如果你不想看文縐縐的document,那就去解幾個死鎖問題


推薦閱讀:

為什麼很多mysql課程不推薦用物理外鍵?

TAG:資料庫 | 軟體開發 | 數據 | 資料庫管理員DBA | 資料庫事務 |