MySQL - 并发事务问题及解决方案
文章目錄
- 生猛干貨
- Pre
- 臟讀
- 不可重復讀
- 幻讀
- Solutions
- 搞定MySQL
生猛干貨
帶你搞定MySQL實戰,輕松對應海量業務處理及高并發需求,從容應對大場面試
Pre
MySQL - 多版本控制 MVCC 機制初探
中我們初步了解了 MVCC 的原理及其實現。 隨著數據庫并發事務處理能力的增強,數據庫資源的利用率也會大大提高,從而提高了數據庫系統的事務吞吐量,可以支持更多的用戶并發訪問。
但并發事務處理也會帶來一些問題,如:臟讀、不可重復讀、幻讀等等
臟讀
一個事務正在對一條記錄做修改,在這個事務完成并提交前,這條記錄的數據就處于不一致狀態;這時,另一個事務也來讀取同一條記錄,如果不加控制,第二個事務讀取了這些“臟”數據,并據此做進一步的處理,就會產生未提交的數據依賴關系。這種現象被形象的叫作"臟讀"(Dirty Reads)。
簡答來說,讀取了其他事務未提交的數據
不可重復讀
一個事務在讀取某些數據后的某個時間,再次讀取以前讀過的數據,卻發現其讀出的數據已經發生了改變、或某些記錄已經被刪除了!這種現象就叫作“ 不可重復讀”(Non-Repeatable Reads)。
幻讀
一個事務按相同的查詢條件重新讀取以前檢索過的數據,卻發現其他事務插入了滿足其查詢條件的新數據,這種現象就稱為“幻讀”(Phantom Reads)。
Solutions
MySQL 數據庫是通過事務隔離級別來解決上述問題的。
我們舉例說明“臟讀”和“不可重復讀”的問題
【 RC 隔離級別】
MySQL 中默認的事務隔離級別是 RR,這里設置成 RC 隔離級別,此時提交事務 B 修改 id=1 的數據之后,事務 A 進行同樣的查詢操作,后一次和前一次的查詢結果不一樣,這就是不可重復讀(重新讀取產生的結果不一樣了)。這里事務 A 讀到了事務 B 提交的數據,即是“臟讀”。
【RR隔離級別】
下面我們來看看在mysql默認的RR隔離級別下的情況。當 teacher_id=1時,事務 A 先進行一次讀取操作,事務 B 中間修改了 id=1 的數據并提交,事務 C 也插入了一條數據并提交。事務 A 第二次讀到的數據和第一次完全相同。所以說它是可重讀的。
【幻讀】
行鎖可以防止不同事務版本的數據在修改提交時造成數據沖突的情況。但如何避免別的事務插入數據造成的問題呢。我們先來看看在 RC 隔離級別下的處理過程。
如下圖所示,事務 A 修改了所有 teacher_id=30 的數據,但是當事務 B INSERT 新數據后,事務 A 發現莫名其妙的多了一行 teacher_id=30 的數據, 而且沒有被之前的 UPDATE語句所修改,這就是“當前讀”的幻讀問題。
跟上面的例子一樣,也是在 RC 事務隔離級別下,這時事務 B INSERT 了一條數據,并提交,而事務 A 讀到了事務 B 新插入的數據。這也是幻讀,如下圖所示。
這里就需要重點注意不可重復讀和幻讀的區別了。前面講了它們的含義,這個提醒大家的是:不可重復讀重點在于 UPDATA 和 DELETE,而幻讀的重點在于 INSERT。它們之間最大的區別是如何通過鎖機制來解決它們產生的問題。這里說的鎖只是使用悲觀鎖機制。
那么在 RR 隔離級別下,事務 A 在 UPDATE 后加鎖,事務 B 無法插入新數據,這樣事務 A在 UPDATE 前后讀的數據保持一致,避免了幻讀。
跟上面的案例一樣,也是在 RR 事務隔離級別下,事務 A 在 UPDATE 后加鎖,對于其他兩個事務,事務 B 和事務 C 的 INSERT 操作,就必須等事務 A 提交后,才能繼續執行。這里就用到了“鎖”,這里使用的是 Gap 鎖,后面會詳細講解。它和上面的情況一樣,解決了“幻讀”的發生,如下圖所示。
搞定MySQL
總結
以上是生活随笔為你收集整理的MySQL - 并发事务问题及解决方案的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MySQL - 多版本控制 MVCC 机
- 下一篇: MySQL - 锁机制初探