什么是事務(wù)
事務(wù)是指由一系列數(shù)據(jù)庫操作組成的一個完整的邏輯過程,這個過程中的所有操作要么都成功,要么都不成功。比如:常見的例子就是銀行轉(zhuǎn)賬的例子,一次轉(zhuǎn)賬操作會包含多個數(shù)據(jù)庫操作,而這些數(shù)據(jù)庫操作需要放到一個事務(wù)當(dāng)中,保證其要么都成功,要么都不成功。
什么是ACID
ACID是事務(wù)的四個特性,指的是atomicity,原子性;consistency,一致性;isolation,隔離性;durability,持久性。
- 原子性(atomicity): 指所有在事務(wù)中的操作要么都成功,要么都不成功,所有的操作都不可分割,沒有中間狀態(tài)。一旦某一步執(zhí)行失敗,就會全部回滾到初始狀態(tài)。
- 一致性(consistency): 指的是邏輯上的一致性,即所有操作是符合現(xiàn)實當(dāng)中的期望的。具體參考下一節(jié)
- 隔離性(isolation): 即不同事務(wù)之間的相互影響和隔離的程度。比如,不同的隔離級別,事務(wù)的并發(fā)程度也不同,最強的隔離狀態(tài)是所有的事務(wù)都是串行化的(serializable)(即一個事務(wù)完成之后才能進行下一個事務(wù)),這樣并發(fā)性也會降到最低,在保證了強一致性的情況下,性能也會受很大影響,所以在實際工程當(dāng)中,往往會折中一下。
- 持久性(durability): 可以簡單地理解為事務(wù)執(zhí)行完畢后數(shù)據(jù)不可逆并持久化存儲于存儲系統(tǒng)當(dāng)中
理解一致性
實際上我們通常說的數(shù)據(jù)庫事務(wù)的一致性和分布式系統(tǒng)的一致性并不是一個概念。這里可以區(qū)分成“內(nèi)部一致性”和“外部一致性”?!皟?nèi)部一致性”搞數(shù)據(jù)庫的人很少這么說,一般就直接說一致性,更準確的說是“Consistency in ACID”(“事務(wù) ACID 屬性中的一致性”);“外部一致性”是針對分布式系統(tǒng)而言的,分布式領(lǐng)域提及的 Consistency 表示系統(tǒng)的正確性模型,著名的也是臭名昭著的 CAP 理論中的 C 就是這個范疇的。這主要是由于分布式系統(tǒng)寫入和讀取都可能不在同一臺機器上,而這必然會有一段時間導(dǎo)致不同機器上所存的數(shù)據(jù)不一致的情況,這就是所謂的“不一致時間窗口”。
內(nèi)部一致性
要理解內(nèi)部一致性也就是我們通常所說的ACID中的一致性,就必須從反面考慮什么情況下是不一致的。不一致的情況主要有以下幾種情況:

- 修改丟失:丟失修改是事務(wù)A和B先后更改數(shù)據(jù)數(shù)據(jù)x(假設(shè)初始是x0),但是在A未正式更改前,B已經(jīng)讀取了原先的數(shù)據(jù)x0,最后A更改后為x1,B更改的并不是A更新后的x1,而是更改的x0,更改后假設(shè)為x2,這時x2將x1覆蓋了,相當(dāng)于事務(wù)A針對x的更改丟失了。
- 臟讀: 事務(wù)T1讀取了T2更改的x,但是T2在實際存儲數(shù)據(jù)時可能出錯回滾了,這時T1讀取的實際是無效的數(shù)據(jù),這種情況下就是臟讀
- 不可重復(fù)讀:是說在T1讀取x時,由于中間T2更改了x,所以T1前后兩次讀取的x值不相同,這就是所謂的不可重復(fù)讀
- 幻讀:在T1讀取符合某個條件的所有記錄時,T2增加了一條符合該條件的記錄,這就導(dǎo)致T1執(zhí)行過程中前后讀取的記錄可能不一致,即T2之后讀取時會多出一條記錄。
其中前三種(丟失修改、不能重復(fù)讀、臟讀)都是由于并發(fā)事務(wù)在修改同一份數(shù)據(jù)的時候?qū)е碌膯栴},此類問題可以通過對同一個資源加鎖的方式來解決,而最后一種情況是由于不同事務(wù)并發(fā)時,新增數(shù)據(jù)導(dǎo)致的問題,對于新增的記錄是無法加鎖的,此種情況只能通過事務(wù)的串行化來解決。而串行化與并發(fā)是矛盾的,所以要在性能和事務(wù)的一致性強度上取得一個平衡,就涉及到不同的隔離等級,關(guān)于隔離等級,詳見理解隔離性一節(jié)。
外部一致性
在分布式系統(tǒng)中我們所說的一致性,也就是外部一致性,通常會分為強一致性,弱一致性,還有最終一致性,而要理解外部一致性,需要對CAP理論(Consistency,Availability和Partition Tolerance)有所了解,關(guān)于CAP詳見CAP定理一節(jié)。
- 強一致性:指系統(tǒng)中的某個數(shù)據(jù)被成功更新后,后續(xù)任何對該數(shù)據(jù)的讀取操作都將得到更新后的值
- 弱一致性:弱一致性是相對于強一致性而言,它不保證總能得到最新的值;
- 最終一致性:是弱一致性的特殊形式,即保證在沒有新的更新的條件下,經(jīng)過一段“不一致時間窗口”,最終所有的訪問都是最后更新的值。最常見的是DNS服務(wù),更新域名指向的機器后,多級緩存要等到expiration time的時候才會更新,但是隨著時間的推移,最終數(shù)據(jù)會趨于一致。
理解隔離性
事務(wù)的隔離級別從低到高有
讀未提交(Read uncommitted)、讀提交(read committed)、可重復(fù)讀(repeatable read)和串行化(Serializable)
- Read Uncommitted:事務(wù)讀數(shù)據(jù)時不會加鎖,寫數(shù)據(jù)時會有行級共享鎖。假設(shè)事務(wù)1先于事務(wù)2,當(dāng)事務(wù)1更新數(shù)據(jù)的時候,事務(wù)2可以讀取事務(wù)1未提交的數(shù)據(jù),但是不能更新事務(wù)1正在更新的數(shù)據(jù)。而如果事務(wù)1只是讀數(shù)據(jù),那么事務(wù)2既可以讀數(shù)據(jù),也可以更新數(shù)據(jù)。
這種情況下無法規(guī)避臟讀,不可重復(fù)讀的問題。 - Read Committed:即在一個事務(wù)修改數(shù)據(jù)過程中,如果事務(wù)還沒提交,其他事務(wù)不能讀該數(shù)據(jù),或者說只能讀取committed的數(shù)據(jù)。事務(wù)讀數(shù)據(jù)的瞬間會加行級共享鎖,一旦讀完該行,立即釋放該行級共享鎖;而寫數(shù)據(jù)的瞬間會加行級排它鎖,直到事務(wù)結(jié)束。這種情況下就避免了臟讀,但是卻不能避免不可重復(fù)讀的問題
- Repeatable Read:當(dāng)然就再升一級,為的就是避免不可重復(fù)讀的問題,所以名字叫repeatable read。怎么實現(xiàn)的呢,我們知道read committed是,事務(wù)讀操作只在讀的一瞬間加鎖,讀完這行就釋放鎖了,而repeatable read級別是讀的一瞬間加鎖,但是一直到事務(wù)結(jié)束才釋放鎖。但是repeatable read不能解決幻讀的問題,因為幻讀是增加記錄,并不是更改原先的記錄。
- Serialization:到達這一級別的隔離,可以徹底解決一致性的所有問題。一般來說是通過加表鎖來解決串行化的問題。
CAP定理
CAP理論主要是針對分布式存儲系統(tǒng)的,C是指Consistency一致性,A是指Availability可用性,P是指Partition tolerance分區(qū)容忍性。CAP定理認為分布式系統(tǒng)中這三個特性最多只能同時滿足兩個特性。下面我們來分別看下這三個特性究竟是什么意思。

- 一致性(Consistency): 指在分布式系統(tǒng)中的所有數(shù)據(jù)備份,在同一時刻是否同樣的值。(等同于所有節(jié)點訪問同一份最新的數(shù)據(jù)副本)
- 可用性(Availability): 在集群中一部分節(jié)點故障后,集群整體是否還能響應(yīng)客戶端的讀寫請求。(對數(shù)據(jù)更新具備高可用性)
- 分區(qū)容忍性(Partition tolerance): 即當(dāng)節(jié)點之間無法正常通信時,就產(chǎn)生了分區(qū),而分區(qū)產(chǎn)生后,依然能夠保證服務(wù)可用,那么我們就說系統(tǒng)是分區(qū)容忍的。顯然如果節(jié)點越多,且備份越多,分區(qū)容忍度就越高(因為即便是其中一個或多個節(jié)點掛了,仍然有其它節(jié)點和備份可用)。
那么,為什么說三個特性無法全部保證呢?首先,假如我們要保證分區(qū)容忍性,必然要做多個副本節(jié)點,而這必然會帶來一致性的問題,即保證多個節(jié)點的數(shù)據(jù)是相同的,但是,要讓多個節(jié)點數(shù)據(jù)相同,就必須要花時間去復(fù)制數(shù)據(jù),這還是能夠正常通信的情況下,那么在數(shù)據(jù)復(fù)制的過程中為了保持一致性,就不能對外提供服務(wù),所以這段時間就無法滿足可用性的問題。
實際工程通常會采取一些折中措施,比如并不保證強一致性,只保證最終一致性,什么意思呢?比如,有三個數(shù)據(jù)節(jié)點互為備份,某份數(shù)據(jù)在節(jié)點A更改后,需要將更改復(fù)制到節(jié)點B和C,假設(shè)復(fù)制過程中,有客戶訪問該數(shù)據(jù),那么此時不保證是一致的,即訪問A節(jié)點的用戶得到的是最新數(shù)據(jù),而訪問B和C節(jié)點的用戶得到是老數(shù)據(jù),但是最終,數(shù)據(jù)會復(fù)制完成,所以最終A、B、C三個節(jié)點的數(shù)據(jù)是一致的。(比如像文章點贊這種數(shù)據(jù),延遲下也沒有關(guān)系啦)