一、事務的特性
acid:
1、原子性(atomicity)
事務是最小的不可分割單元。只有做完和回滾,沒有中間狀態。
2、一致性(consistency)
資料庫總是從乙個一致的狀態轉換到另乙個一致的狀態。這個有些容易和隔離性弄混淆,其實二者有內在的因果關係。正是隔離性的級別,造成了一致性的差異,這裡的一致性可以簡單理解為在某個時間後,同樣的讀取操作可以得到同樣的結果。
強一致性:讀操作可以立即讀到提交的更新操作。
弱一致性:提交的更新操作,不一定立即會被讀操作讀到,此種情況會存在乙個不一致視窗,指的是讀操作可以讀到最新值的一段時間。
最終一致性:是弱一致性的特例。事務更新乙份資料,最終一致性保證在沒有其他事務更新同樣的值的話,最終所有的事務都會讀到之前事務更新的最新值。如果沒有錯誤發生,不一致視窗的大小依賴於:通訊延遲,系統負載等。
其他一致性變體還有:
單調一致性:如果乙個程序已經讀到乙個值,那麼後續不會讀到更早的值。
會話一致性:保證客戶端和伺服器互動的會話過程中,讀操作可以讀到更新操作後的最新值。
3、隔離性(isolation)
乙個事務未提交前對其他事務事不可見的。在事務併發操作時,可能出現的問題有:
髒讀:事務a修改了乙個資料,但未提交,事務b讀到了事務a未提交的更新結果,如果事務a提交失敗,事務b讀到的就是髒資料。
可重複讀:在同乙個事務中,對於同乙份資料讀取到的結果不一致。比如,事務b在事務a提交前讀到的結果,和提交後讀到的結果可能不同。不可重複讀出現的原因就是事務併發修改記錄,要避免這種情況,最簡單的方法就是對要修改的記錄加鎖,這回導致鎖競爭加劇,影響效能。另一種方法是通過mvcc可以在無鎖的情況下,避免不可重複讀。
幻讀:在同乙個事務中,同乙個查詢多次返回的結果不一致。事務a新增了一條記錄,事務b在事務a提交前後各執行了一次查詢操作,發現後一次比前一次多了一條記錄。幻讀是由於併發事務增加記錄導致的,這個不能像不可重複讀通過記錄加鎖解決,因為對於新增的記錄根本無法加鎖。需要將事務序列化,才能避免幻讀。
簡單來說髒讀時讀到了未提交事務修改的資料,最終事務被回滾,中間態的資料被讀出。可重複讀是資料庫事並行時巢狀影響,某個事務中前後兩次讀取,因為另乙個事務提交資料更新而不同(修改加鎖)。幻讀粗看很像不可重複讀,二者區別在於,不可重複讀是對同乙份資料讀取的結構前後不一致,幻讀是同乙個查詢前後返回結果不一致,前者說的是本身被資料修改,後者說的除了資料本身被修改,還包含資料條數增加或減少。這裡之所以要分成兩個級別是因為,不可重複讀通過更新時加鎖涉及到的資料或類似的思路即可解決,但是幻讀中增加資料的情況,在讀之前資料壓根不存在,無從加鎖,解決上必須另想辦法(限制事務並行)。
為解決上述問題,資料庫有4種不同的隔離級別:
read uncommitted:最低的隔離級別,什麼都不需要做,乙個事務可以讀到另乙個事務未提交的結果。所有的併發事務問題都會發生。
未提交讀,即不做隔離控制。
read committed:只有在事務提交後,其更新結果才會被其他事務看見。可以解決髒讀問題。
提交讀,oracle的預設事務級別,可解決髒讀問題,即不存在被讀後,事務又回滾的情況。
repeated read:在乙個事務中,對於同乙份資料的讀取結果總是相同的,無論是否有其他事務對這份資料進行操作,以及這個事務是否提交。可以解決髒讀、不可重複讀。
可重複讀,mysql的預設事務級別,可解決髒讀和不可重複讀的問題,但無法解決幻讀(幻行)問題,幻讀資料庫通過多版本併發控制(mvcc,mutiversion concurrency control)解決。
serialization:事務序列化執行,隔離級別最高,犧牲了系統的併發性。可以解決併發事務的所有問題。
可序列化,最高的隔離級別,強制事務序列化。
通常,在工程實踐中,為了效能的考慮會對隔離性進行折中。
綜上:
4、永續性(durability)
事務提交後,事務所做的修改將一直儲存在資料庫中。
二、mysql關於不可重複讀與幻讀的解決方案
1、加鎖:
如果使用鎖機制來實現這兩種隔離級別,在可重複讀中,該sql第一次讀取到資料後,就將這些資料加鎖,其它事務無法修改這些資料,就可以實現可重複讀了。但這種方法卻無法鎖住insert的資料,所以當事務a先前讀取了資料,或者修改了全部資料,事務b還是可以insert資料提交,這時事務a就會發現莫名其妙多了一條之前沒有的資料,這就是幻讀,不能通過行鎖來避免。需要serializable隔離級別 ,讀用讀鎖,寫用寫鎖,讀鎖和寫鎖互斥,這麼做可以有效的避免幻讀、不可重複讀、髒讀等問題,但會極大的降低資料庫的併發能力。所以說不可重複讀和幻讀最大的區別,就在於如何通過鎖機制來解決他們產生的問題。
2、mvcc:
悲觀鎖和樂觀鎖
正如其名,它指的是對資料被外界(包括本系統當前的其他事務,以及來自外部系統的事務處理)修改持保守態度,因此,在整個資料處理過程中,將資料處於鎖定狀態。悲觀鎖的實現,往往依靠資料庫提供的鎖機制(也只有資料庫層提供的鎖機制才能真正保證資料訪問的排他性,否則,即使在本系統中實現了加鎖機制,也無法保證外部系統不會修改資料)。
在悲觀鎖的情況下,為了保證事務的隔離性,就需要一致性鎖定讀。讀取資料時給加鎖,其它事務無法修改這些資料。修改刪除資料時也要加鎖,其它事務無法讀取這些資料。
即上面說的互斥讀寫鎖。
相對悲觀鎖而言,樂觀鎖機制採取了更加寬鬆的加鎖機制。悲觀鎖大多數情況下依靠資料庫的鎖機制實現,以保證操作最大程度的獨占性。但隨之而來的就是資料庫效能的大量開銷,特別是對長事務而言,這樣的開銷往往無法承受。而樂觀鎖機制在一定程度上解決了這個問題。樂觀鎖,大多是基於資料版本( version )記錄機制實現。何謂資料版本?即為資料增加乙個版本標識,在基於資料庫表的版本解決方案中,一般是通過為資料庫表增加乙個 「version」 欄位來實現。讀取出資料時,將此版本號一同讀出,之後更新時,對此版本號加一。此時,將提交資料的版本資料與資料庫表對應記錄的當前版本資訊進行比對,如果提交的資料版本號大於資料庫表當前版本號,則予以更新,否則認為是過期資料。
這裡類似於併發思想中的cas(compare and swap),更新時,資料與期待一致(這裡是版本號)才更新。
要說明的是,mvcc的實現沒有固定的規範,每個資料庫都會有不同的實現方式,這裡討論的是innodb的mvcc。
更詳細解讀:
參考1.
2.《高效能mysql>>第三版,p6-9;
3.4.;
資料庫事務
事件是訪問並可能更新各種資料項的乙個程式執行單元。事件由事務開始與事務結束之間執行的全體操作組成。為了保證資料完整性,資料庫系統需要維護事務的以下性質 原子性 atomicity 事務中的操作要麼全部成功,要麼全部失敗。一致性 consistency 事務執行前後要保持資料庫的一致性。隔離性 iso...
資料庫 事務
資料庫事務 database transaction 是指作為單個邏輯工作單元執行的一系列操作。事務處理可以確保除非事務性單元內的所有操作都成功完成,否則不會永久更新面向資料的資源。通過將一組相關操作組合為乙個要麼全部成功要麼全部失敗的單元,可以簡化錯誤恢復並使應用程式更加可靠。乙個邏輯工作單元要成...
資料庫事務
這段時間面試,由於基礎不是特別好,遇到一些要筆試的公司。就會表示出來 今天有人問我,資料庫事務 是什麼。我只感覺十分熟悉。但是又說不出所以然。回來找了一下,現在整理記錄 1 定義 資料庫事務 database transaction 是指作為單個邏輯工作單元執行的一系列操作。事務處理可以確保除非事務...