一、什么是事務?
? ? ? ? MySQL的事務(Transaction)是一組由數據庫管理系統(DBMS)執行的一個或多個SQL語句的集合,這些SQL語句作為一個單獨的工作單元執行。事務的主要目的是確保數據庫的一致性和完整性,特別是在并發環境下。這些操作要么全部都執行,要么都不執行, 它是一個不可分割的工作執行單元。
二、事務的特性
????????事務是由[MySQL 的引擎]來實現的,我們常見的 InnoDB 引擎它是支持事務的。不過并不是所有的引擎都能支持事務,比如 MySQL 原生的 MyISAM 引擎就不支持事務,也正是這樣,所以大多數 MySQL 的引擎都是用 InnoDB。
????????事務有四個關鍵特性,通常被稱為ACID特性。這四個特性是:
1、原子性(Atomicity):
????????事務中的所有操作要么全部成功,要么全部失敗。即事務是一個不可分割的工作單元。即使在事務執行過程中發生了錯誤,事務中的任何更改都不會保留,系統會回滾(Undo)所有已經執行的操作,使數據庫回到事務開始之前的狀態。
2、一致性(Consistency):
????????事務從一個一致的數據庫狀態轉換到另一個一致的數據庫狀態。數據庫在事務開始之前和結束之后都必須滿足所有的定義的約束、觸發器和規則。換句話說,事務開始前和事務結束后數據應該是一致的,例如張三有300,李四有400,那么無論他們如何轉賬,總錢數700應該是不變的。
3、隔離性(Isolation):
????????事務的執行過程對其他事務是隔離的。即使多個事務并發執行,每個事務也無法看到其他事務未提交的中間狀態,即多個并發事務直接要相互隔離,互不干擾。隔離性保證了并發事務的正確執行。MySQL提供了不同的隔離級別來控制事務之間的隔離程度,包括未提交讀、提已交讀、可重復讀和可序列化。
4、持久性(Durability):
????????一旦事務提交,所做的更改將永久保存到數據庫中,即使發生系統故障,數據也不會丟失。持久性通過將事務的日志記錄到持久存儲設備(如磁盤)上來實現。提交事務后,系統保證即使系統崩潰,也能通過日志恢復已提交的數據。
InnoDB 引擎通過什么技術來保證事務的這四個特性的呢?
- 持久性是通過 redo log (重做日志)來保證的;
- 原子性是通過 undo log(回滾日志) 來保證的;
- 隔離性是通過 MVCC(多版本并發控制)或鎖機制來保證的;
- 一致性則是通過持久性+原子性+隔離性來保證;
簡單知道一下即可,這是一個非常復雜的底層邏輯。
三、并發事務下三類數據讀取問題與數據更新
???????MySQL 服務端是允許多個客戶端連接的,這意味著 MySQL 會出現同時處理多個事務的情況。主要有三類數據讀取問題:
1、臟讀(Dirty Read):
????????一個事務能夠讀取另一個事務尚未提交的數據。這種情況會導致讀取的數據可能在未來被回滾,從而導致讀取到不正確的數據。
?示例:事務A更新了某行數據,然后事務B讀取了這些更新的數據。然而,事務A隨后回滾了,這意味著事務B讀到了未提交的、隨后被撤銷的數據。2、不可重復讀(Non-Repeatable Read):
????????一個事務在讀取某行數據后,再次讀取該行數據時,發現數據已經被另一個已提交的事務修改了,兩次讀取同一數據的結果不一致。
示例:事務A在某時刻讀取了一行數據。然后事務B更新了這行數據并提交。事務A再次讀取該行數據時,發現數據已經改變。
3、幻讀(Phantom Read):
? ? ? ? 一個事務按照條件查詢數據時,沒有對應的數據行,但是在插入數據時,又發現這行數據已經存在,好像出現了“幻影”。
示例:事務A讀取了滿足某個條件的所有數據行。事務B插入了一些滿足這個條件的新數據行并提交。事務A再次讀取時,發現多了一些之前沒有的數據行。
????????我們對三類數據讀取問題做一個總結就是:
臟讀:讀到其他事務未提交的數據;
不可重復讀:前后讀取的數據不一致;
幻讀:前后讀取的記錄數量不一致。
????????在并發事務下,不僅會遇到數據讀取問題,還會遇到數據更新問題,主要有以下兩類:
丟失更新(Lost Update):
????????兩個事務都讀取同一數據并修改它們中的一個,導致一個事務的修改被另一個事務的修改覆蓋,最終的更新丟失。這種情況通常發生在沒有合適的鎖機制來同步并發事務時。
示例:事務A和事務B都讀取了同一行數據,然后事務A和事務B都修改了這行數據并提交。事務A的修改被事務B的修改覆蓋,導致事務A的更新丟失。
不可重復寫(Non-Repeatable Write):
????????一個事務在寫入某行數據后,另一個事務修改了這行數據。當第一個事務再次寫入這行數據時,發現數據已經被另一個事務改變了。這種情況導致數據的不一致性。
示例:事務A和事務B同時讀取同一行數據。事務A先修改了數據并提交,事務B再修改數據并提交,事務A的更改可能沒有被考慮在內。
四、事務隔離級別
前面我們提到,當多個事務并發執行時可能會遇到【臟讀、不可重復讀、幻讀】的現象,這些現象會對事務的一致性產生不同程序的影響。SQL 標準提出了四種隔離級別來規避這些現象,隔離級別越高,性能效率就越低,這四個隔離級別如下:
- 讀未提交:指一個事務還沒提交時,它做的變更就能被其他事務看到。
- 讀提交:指一個事務提交之后,它做的變更才能被其他事務看到。
- 可重復讀:指一個事務執行過程中看到的數據,一直跟這個事務啟動時看到的數據是一致的,MySQL InnoDB 引擎的默認隔離級別。
- 串行化:會對記錄加上讀寫鎖,在多個事務對這條記錄進行讀寫操作時,如果發生了讀寫沖突的時候,后訪問的事務必須等前一個事務執行完成,才能繼續執行。
????????不同的數據庫廠商對 SQL 標準中規定的 4 種隔離級別的支持不一樣,有的數據庫只實現了其中幾種隔離級別,MySQL 雖然支持 4 種隔離級別,但是與SQL 標準中規定的各級隔離級別允許發生的現象卻有些出入。(隔離級別的定義由SQL提出,這不是MySQL規定的)
????????MySQL InnoDB 引擎在可重復讀隔離級別下,可以很大程度上避免幻讀現象的發生,所以 MySQL 并不會使用串行化隔離級別來避免幻讀現象的發生,因為使用串行化隔離級別會嚴重影響性能(畢竟是悲觀鎖)。而關于為什么可以很大程度上避免幻讀現象的發生,這就是涉及到了一個概念叫做MVCC。
????????多版本并發控制(MVCC,Multi-Version Concurrency Control)是一種用于提高數據庫系統并發性能的技術。它允許多個事務在不加鎖的情況下并發讀取和寫入數據,從而避免了許多鎖競爭問題。MVCC通過保存數據的多個版本來實現一致性和隔離性。關于更多MVCC的東西可以看我的另一篇文章。?