事物所具有的特質是什么的文章?
在工作中,經常會接觸到事務這個概念。涉及到事務,大家首先想到的就是事務的四個特性:ACID。
1.原子性(Atomicity)
1.1什么是原子性
一般來說,原子是指不能分解成小部分的東西。這個詞在計算的不同分支中意味著相似但又微妙不同的東西。例如,在多線程編程中,如果一個線程執行一個原子操作,這意味著另一個線程無法看到該操作的一半結果。系統只能處于操作之前或操作之后的狀態,而不是介于兩者之間的狀態。 ACID原子性的定義特征是:能夠在錯誤時中止事務,丟棄該事務進行的所有寫入變更的能力。
1.2 如何實現原子性
WAL(預寫日志) 是用于保證事務的原子性和持久性。簡單來講,事務更新數據之前,先寫日志,然后在更新數據。當系統崩潰時,如果事務還沒寫WAL,那整個數據依然一致。如果事務只寫了WAL,未更新具體的數據頁后崩潰,那恢復流程可以根據WAL日志,重做相關操作,保證數據一致性。
2.一致性(Consistency)
ACID一致性的概念是,對數據的一組特定陳述必須始終成立。即不變量(invariants)。例如,在會計系統中,所有賬戶整體上必須借貸相抵。如果一個事務開始于一個滿足這些不變量的有效數據庫,且在事務處理期間的任何寫入操作都保持這種有效性,那么可以確定,不變量總是滿足的。 原子性,隔離性和持久性是數據庫的屬性,而一致性(在ACID意義上)是應用程序的屬性。應用可能依賴數據庫的原子性和隔離屬性來實現一致性,但這并不僅取決于數據庫。
3.隔離性(Isolation)
3.1什么是隔離性
大多數數據庫都會同時被多個客戶端訪問。如果它們各自讀寫數據庫的不同部分,這是沒有問題的,但是如果它們訪問相同的數據庫記錄,則可能會遇到并發問題(競爭條件(race conditions))。 ACID意義上的隔離性意味著,同時執行的事務是相互隔離的:它們不能相互冒犯。
如果兩個事務不觸及相同的數據,它們可以安全地并行(parallel) 運行,因為兩者都不依賴于另一個。當一個事務讀取由另一個事務同時修改的數據時,或者當兩個事務試圖同時修改相同的數據時,并發問題(競爭條件)才會出現。出于這個原因,數據庫一直試圖通過提供事務隔離(transaction isolation) 來隱藏應用程序開發者的并發問題。
serializable級別的隔離,保證事務的效果與連續運行(即一次一個,沒有任何并發)是一樣的,可以保證事務地安全執行。但是在Serializable隔離級別,事務并發度很低,整個數據庫的性能肯定不高。這時候,數據庫開發人員有提出了四種不同的隔離級別,來平衡事務并發度與隔離性,這四個隔離級別分別是:
讀未提交(Read Uncommitted):可以讀取未提交的記錄。
讀已提交(Read Committed):事務中只能看到已提交的修改。
可重復讀(Repeatable Read):解決了不可重復讀問題(MySQL 默認隔離級別)
序列化(Serializable):最高隔離級別。
RU,RC和RR由于降低了隔離要求,自然在讀取數據時,會產生各種異常(上帝為你打開一扇門的同時,肯定也為你關上一扇窗):
RU會讀取其他事務未提交的數據,這就產生了臟讀,臟讀取意味著另一個事務可能會只看到一部分更新,或者看到的數據已經被回滾了。
RC級別的隔離,會產生不可重復讀的問題。所謂不可重復讀是指在一個事務內根據同一個條件對行記錄進行多次查詢,但是搜出來的結果卻不一致。發生不可重復讀的原因是在多次搜索期間查詢條件覆蓋的數據被其他事務修改了。
RR級別的隔離,會產生幻讀問題。幻讀,并不是說兩次讀取獲取的結果集不同,幻讀側重的方面是某一次的 select 操作得到的結果所表征的數據狀態無法支撐后續的業務操作。更為具體一些:select 某記錄是否存在,不存在,準備插入此記錄,但執行 insert 時發現此記錄已存在,無法插入,此時就發生了幻讀。
3.2 如何支持隔離性
一般數據庫不會考慮工作在RU隔離級別,因為讀臟數據會引起太多的問題。數據庫一般工作在RC或RR隔離級別,快照隔離級別就可以支持RC或RR隔離級別,所以數據庫一般會實現快照隔離級別。
快照隔離的實現通常使用寫鎖來防止臟寫,這意味著進行寫入的事務會阻止另一個事務修改同一個對象。但是讀取不需要任何鎖定。從性能的角度來看,快照隔離的一個關鍵原則是:讀不阻塞寫,寫不阻塞讀。這允許數據庫在處理一致性快照上的長時間查詢時,可以正常地同時處理寫入操作。且兩者間沒有任何鎖定爭用。
為了實現快照隔離,數據庫必須保留一個對象的幾個不同的提交版本,因為各種正在進行的事務可能需要看到數據庫在不同的時間點的狀態。因為它并排維護著多個版本的對象,所以這種技術被稱為多版本并發控制(MVCC, multi-version concurrentcy control)。
最高的隔離級別:Serializable,一般是通過2PL來實現, 一階段申請,一階段釋放。讀寫都要加鎖。
4.持久性(Durability)
數據庫系統的目的是,提供一個安全的地方存儲數據,而不用擔心丟失。持久性 是一個承諾,即一旦事務成功完成,即使發生硬件故障或數據庫崩潰,寫入的任何數據也不會丟失。