1. 程式人生 > 實用技巧 >MySQL鎖機制與事務隔離級別

MySQL鎖機制與事務隔離級別

首先推薦大家一套MySQL超詳細的學習資料,你值得擁有!

https://www.bilibili.com/video/BV1fx411X7BD

MySQL基礎入門-mysql教程-資料庫實戰(MySQL基礎+MySQL高階+MySQL優化+MySQL34道作業題)

什麼是事務?

事務是由一組SQL語句組成的邏輯處理單元,事務具有以下4個屬性,通常簡稱為事務的ACID屬性。

  原子性(Atomicity):事務是一個原子操作單元,其對資料的修改,要麼全都執行,要麼全都不執行。

  一致性(Consistent):在事務開始和完成時,資料都必須保持一致狀態。這意味著所有相關的資料規則都必須應用於事務的修改,以保持資料的完整性;事務結束時,所有的內部資料結構(如B樹索引或雙向連結串列)也都必須是正確的。

  隔離性(Isolation):資料庫系統提供一定的隔離機制,保證事務在不受外部併發操作影響的“獨立”環境執行。這意味著事務處理過程中的中間狀態對外部是不可見的,反之亦然。

  永續性(Durable):事務完成之後,它對於資料的修改是永久性的,即使出現系統故障也能夠保持。

事務的實現原理

1、MySQL的日誌系統

日誌系統主要有Redo Log(重做日誌)、Undo Log和binlog(歸檔日誌)。Redo Log是InnoDB儲存引擎層的日誌,binlog是MySQL Server層記錄的日誌, 兩者都是記錄了某些操作的日誌(不是所有),自然有些重複(但兩者記錄的格式不同)

2、事務實現原理

通過上面我們可以知道,事務的特點為:原子性、永續性、隔離性、一致性,是什麼機制才能保證事務的這四個特性呢?

事務的原子性是通過undo log來實現的

事務的持久是通過redolog來實現的

事務的隔離性是通過(讀寫鎖+MVCC)來實現的

事務的一致性是通過原子性、永續性、隔離性來實現的

2.1.1、原子性實現原理---Undo Log

●Undo Log是為了實現事務的原子性,在MySQL資料庫InnoDB儲存引擎中,還用Undo Log來進行多版本併發控制(簡稱MVCC)

●在操作任何資料之前,首先將資料備份到一個地方(這個儲存資料備份的地方稱為Undo Log)。然後進行資料的修改。如果出現了錯誤或者使用者執行了ROLLBACK語句,系統可以利用Undo Log中的備份將資料恢復到事務開始之前的狀態。

●注意: Undo Log是邏輯日誌,可以理解為:

▶ 當delete一條記錄時,Undo Log中會記錄一條對應insert記錄

▶ 當insert一條記錄時,Undo Log中會記錄一條對應delete記錄

▶當update一條記錄時,Undo Log中會記錄一條對應相反的update記錄

2.1.2、永續性實現原理---Redo Log

和Undo Log相反,Redo Log記錄的是資料的備份。在事務提交前,只將Redo Log持久化即可,不需要將資料持久化,當系統崩潰時,雖然資料沒有持久化,但是Redo Log已經持久化,系統可以根據Redo Log的內容,將所有資料恢復到最新的狀態。

2.1.3、隔離性實現原理---鎖

在MySQL的InnoDB儲存引擎中,鎖可以分為兩類:

(1)共享鎖: 共享鎖定是將物件資料變為只讀形式,不能進行更新,所以也成為讀取鎖定,簡稱讀鎖

(2)排他鎖: 排他鎖定是當執行插入/修改/刪除操作的時候,其它事務不能讀取該資料,因此也成為寫入鎖定,簡稱寫鎖

相對其他資料庫而言,MySQL 的鎖機制比較簡單,其最顯著的特點是不同的儲存引擎支援不同的鎖機制。比如,MylSAM、MEMORY儲存引擎採用的是表級鎖,InnoDB儲存引擎既支援行級鎖,也支援表級鎖,但預設情況下是採用行級鎖。

(1)表級鎖: 開銷小、加鎖快、不會出現死鎖、鎖定粒度大、發生鎖衝突的概率最高、併發度最低。

(2)行級鎖:開銷大、加鎖慢、會出現死鎖、鎖定粒度最小、發生鎖衝突的概率最低、併發度也最高。

對於表級鎖和行級鎖並沒有優劣之分,需根據實際需求進行選擇,比如對併發度要求高可以選擇行級鎖等。

3、RedoLog vsUndo Log

(1)Redo Log重做日誌,提供前滾操作;UndoLog是回退日誌,提供回滾操作。

(2)RedoLog通常是物理日誌,記錄的是資料頁的物理修改而不是某一行或某幾行修改成怎樣怎樣,它用來恢復提交後的物理資料頁恢復資料頁,且只能恢復到最後一次提交的位置)。

(3) UndoLog用來回滾行記錄到某個版本。UndoLog一般是邏輯日誌,根據每行記錄進行記錄。

4、淺談binlog

竟然說到了MySQL的日誌,binlog不得不提,它記錄了所有的DDL和DML語句(除了資料查詢語句select),以事件形式記錄,還包含語句所執行的消耗的時間。

binlog三種模式及其優缺點:

(1)statement: 基於SQL語句的模式,某些語句中含有-些函式,例如UUID NOW等在複製過程可能導致資料不一致甚至出錯。

(2)row: 基於的模式,記錄的是行的變化,很安全。但是binlog的磁碟佔用會比其他兩種模式大很多,在一些大表中清除大量資料時在binlog中會生成很多條語句,可能導致從庫延遲變大。

(3)mixed: 混合模式,根據語句來選用是statement還是row模式。

事務的併發問題

單個事務對資料庫的操作是序列的,不會存在併發問題,但是多個事務對資料庫的操作就會產生併發問題,分別為:髒讀、不可重複讀、幻讀。

1、髒讀:事務A讀取了事務B更新的資料,然後B回滾操作,那麼A讀取到的資料是髒資料。通俗講就是事務A讀取了其它事務未提交的資料(髒資料)。

2、不可重複讀:事務 A 多次讀取同一資料,事務 B 在事務A多次讀取的過程中,對資料作了更新並提交,導致事務A多次讀取同一資料時,結果不一致。

3、幻讀:系統管理員A將資料庫中所有學生的成績從具體分數改為ABCDE等級,但是系統管理員B就在這個時候插入了一條具體分數的記錄,當系統管理員A改結束後發現還有一條記錄沒有改過來,就好像發生了幻覺一樣,這就叫幻讀。

小結:不可重複讀的和幻讀很容易混淆,不可重複讀側重於修改和刪除,幻讀側重於新增。解決不可重複讀的問題只需鎖住滿足條件的行,解決幻讀需要鎖表。

事務的隔離級別

下面通過舉例來說明這4種事務隔離級別:

1、讀未提交

(1)開啟一個客戶端A,並設定當前事務模式為read uncommitted(未提交讀),查詢表account的初始值。

(2)在客戶端A的事務提交之前,開啟另一個客戶端B,更新表account。

(3)這時,雖然客戶端B的事務還沒提交,但是客戶端A就可以查詢到B已經更新的資料。

(4)一旦客戶端B的事務因為某種原因回滾,所有的操作都將會被撤銷,那客戶端A查詢到的資料其實就是髒資料。

(5)在客戶端A執行更新語句update account set balance = balance - 50 where id =1,lilei的balance沒有變成350,居然是400,是不是很奇怪,資料不一致啊,如果你這麼想就太天真 了,在應用程式中,我們會用400-50=350,並不知道其他會話回滾了,要想解決這個問題可以採用讀已提交的隔離級別。

2、讀已提交

(1)開啟一個客戶端A,並設定當前事務模式為read committed(未提交讀),查詢表account的所有記錄。

(2)在客戶端A的事務提交之前,開啟另一個客戶端B,更新表account。

(3)這時,客戶端B的事務還沒提交,客戶端A不能查詢到B已經更新的資料,解決了髒讀問題。

(4)客戶端B的事務提交

(5)客戶端A執行與上一步相同的查詢,結果 與上一步不一致,即產生了不可重複讀的問題。

3、可重複讀

(1)開啟一個客戶端A,並設定當前事務模式為repeatable read,查詢account表中id為4的記錄。

(2)在客戶端A的事務提交之前,開啟另一個客戶端B,向account表中插入一條記錄,並提交。

(3)在客戶端B提交之後,同樣地,客戶端A向account表中插入id為4的記錄並再次查詢id為4的記錄,發現主鍵重複但又讀取不到資料,感覺像自己讀過一樣,這就造成了幻讀。