告別 MVCC !
架構大家好,我是小林。
之前寫過一篇 MySQL 的 MVCC 的工作原理,最近有讀者在網站上學習的時候,評論區指出了一些問題。
而這個知識點很重要,面試太常問了,所以,我就重寫了這篇文章!開車!
正文這是我的錢包,共有 100 萬元。
今天我心情好,我決定給你的轉賬 100 萬,最後的結果肯定是我的餘額變為 0 元,你的餘額多了 100 萬元,是不是想到就很開心?
轉賬這一動作在程式裡會涉及到一系列的操作,假設我向你轉賬 100 萬的過程是有下面這幾個步驟組成的:
可以看到這個轉賬的過程涉及到了兩次修改資料庫的操作。
假設在執行第三步驟之後,伺服器忽然掉電了,就會發生一個蛋疼的事情,我的賬戶扣了 100 萬,但是錢並沒有到你的賬戶上,也就是說這 100 萬消失了!
要解決這個問題,就要保證轉賬業務裡的所有資料庫的操作是不可分割的,要麼全部執行成功 ,要麼全部失敗,不允許出現中間狀態的資料。
資料庫中的「事務(Transaction)」就能達到這樣的效果。
我們在轉賬操作前先開啟事務,等所有資料庫操作執行完成後,才提交事務,對於已經提交的事務來說,該事務對資料庫所做的修改將永久生效,如果中途發生發生中斷或錯誤,那麼該事務期間對資料庫所做的修改將會被回滾到沒執行該事務之前的狀態。
事務有哪些特性?事務是由 MySQL 的引擎來實現的,我們常見的 InnoDB 引擎它是支援事務的。
不過並不是所有的引擎都能支援事務,比如 MySQL 原生的 MyISAM 引擎就不支援事務,也正是這樣,所以大多數 MySQL 的引擎都是用 InnoDB。
事務看起來感覺簡單,但是要實現事務必須要遵守 4 個特性,分別如下:
原子性(Atomicity):一個事務中的所有操作,要麼全部完成,要麼全部不完成,不會結束在中間某個環節,而且事務在執行過程中發生錯誤,會被回滾到事務開始前的狀態,就像這個事務從來沒有執行過一樣;
一致性(Consistency):資料庫的完整性不會因為事務的執行而受到破壞,比如表中有一個欄位為姓名,它有唯一約束,也就是表中姓名不能重複,如果一個事務對姓名欄位進行了修改,但是在事務提交後,表中的姓名變得非唯一性了,這就破壞了事務的一致性要求,這時資料庫就要撤銷該事務,返回初始化的狀態。
隔離性(Isolation):資料庫允許多個併發事務同時對其資料進行讀寫和修改的能力,隔離性可以防止多個事務併發執行時由於交叉執行而導致資料的不一致。
永續性(Durability):事務處理結束後,對資料的修改就是永久的,即便系統故障也不會丟失。
InnoDB 引擎通過什麼技術來保證事務的這四個特性的呢?
永續性是通過 redo log (重做日誌)來保證的;
原子性是通過 undo log(回滾日誌) 來保證的;
隔離性是通過 MVCC(多版本併發控制) 或鎖機制來保證的;
一致性則是通過永續性+原子性+隔離性來保證;
這次將重點介紹事務的隔離性,這也是面試時最常問的知識的點。
為什麼事務要有隔離性,我們就要知道併發事務時會引發什麼問題。
並行事務會引發什麼問題?MySQL 服務端是允許多個客戶端連線的,這意味著 MySQL 會出現同時處理多個事務的情況。
那麼在同時處理多個事務的時候,就可能出現髒讀(dirty read)、不可重複讀(non-repeatable read)、幻讀(phantom read)的問題。
接下來,通過舉例子給大家說明,這些問題是如何發生的。
髒讀
如果一個事務「讀到」了另一個「未提交事務修改過的資料」,就意味著發生了「髒讀」現象。
舉個栗子。
假設有 A 和 B 這兩個事務同時在處理,事務 A 先開始從資料庫中讀取小林的餘額資料,然後再執行更新操作,如果此時事務 A 還沒有提交事務,而此時正好事務 B 也從資料庫中讀取小林的餘額資料,那麼事務 B 讀取到的餘額資料是剛才事務 A 更新後的資料,即使沒有提交事務。
因為事務 A 是還沒提交事務的,也就是它隨時可能發生回滾操作,如果在上面這種情況事務 A 發生了回滾,那麼事務 B 剛才得到的資料就是過期的資料,這種現象就被稱為髒讀。
不可重複讀
在一個事務內多次讀取同一個資料,如果出現前後兩次讀到的資料不一樣的情況,就意味著發生了「不可重複讀」現象。
舉個栗子。
假設有 A 和 B 這兩個事務同時在處理,事務 A 先開始從資料庫中讀取小林的餘額資料,然後繼續執行程式碼邏輯處理,在這過程中如果事務 B 更新了這條資料,並提交了事務,那麼當事務 A 再次讀取該資料時,就會發現前後兩次讀到的資料是不一致的,這種現象就被稱為不可重複讀。
幻讀
在一個事務內多次查詢某個符合查詢條件的「記錄數量」,如果出現前後兩次查詢到的記錄數量不一樣的情況,就意味著發生了「幻讀」現象。
- Spring中實現非同步呼叫的方式有哪些?
- 帶引數的全型別 Python 裝飾器
- 整理了幾個Python正則表示式,拿走就能用!
- SOLID:開閉原則Go程式碼實戰
- React中如何引入CSS呢
- 一個新視角:前端框架們都卷錯方向了?
- 編碼中的Adapter,不僅是一種設計模式,更是一種架構理念與解決方案
- 手寫程式語言-遞迴函式是如何實現的?
- 一文搞懂模糊匹配:定義、過程與技術
- 新來個阿里 P7,僅花 2 小時,做出一個多執行緒永動任務,看完直接跪了
- Puzzlescript,一種開發H5益智遊戲的引擎
- @Autowired和@Resource到底什麼區別,你明白了嗎?
- CSS transition 小技巧!如何保留 hover 的狀態?
- React如此受歡迎離不開這4個主要原則
- LeCun再炮轟Marcus: 他是心理學家,不是搞AI的
- Java保證執行緒安全的方式有哪些?
- 19個殺手級 JavaScript 單行程式碼,讓你看起來像專業人士
- Python 的"self"引數是什麼?
- 別整一坨 CSS 程式碼了,試試這幾個實用函式
- 再有人問你什麼是MVCC,就把這篇文章發給他!