面試官:說說資料庫事務吧

上古偽神發表於2021-03-10

前言

上一篇說了如何檢視MySQL的執行計劃,今天就來看一下資料庫的事務相關的知識點。

面試官在資料庫這方面最常問的除了sql優化,還有資料庫事務、儲存引擎等相關知識。上期有人說沒有自動門,所以這一期我特地造了自動門,這門沒有四五塊造不下來。

注意:只是CRUD的搬磚工就不需要看了,看了也忘了,只需要拉到最後,點贊、在看、分享,一鍵三連然後收藏起來就行了。

什麼是事務

事務是指是程式中一系列嚴密的邏輯操作,而且所有操作必須全部成功完成,否則在每個操作中所作的所有更改都會被撤消。

通俗點說就是要麼一起活,要麼一起死。

面試官:說說資料庫事務吧

 

事務特性

事務特性就是普通都知道的ACID,那麼什麼是ACID,估計有些貨跟我之前一樣,只知道這個詞,不知道每個字母代表的是什麼,這次就給翻譯翻譯什麼叫TMD驚喜(不,說錯了,是字母),我還特地下了一個有道詞典,浪費了幾十M的流量。

面試官:說說資料庫事務吧

 

A:Atomicity原子性

所謂原子性就是說事務是一個最小的單元,跟原子一樣不可再分割。一個事務中的所有操作要麼全部成功,要麼全部失敗,通過WAL(Write Ahead Log)實現。(HBASE也應用了這個技術)

I:Isolation隔離性

一個事務在操作還未結束之前,對其他事務是不可見的,即一個事務內部的操作及使用的資料對其他的併發事務是隔離的。鎖和多版本控制就符合隔離性。

類似與現在的共享文件:我在編輯文件未儲存之前其他人是不可見的。

D:Durability永續性

一旦事務提交,其所做的修改就會永久儲存到資料庫中。

人也要學會持久,老子沒開車。比如健身,深蹲蹲一半怎麼行。

C:Consistency一致性

資料庫總是從一個一致性的狀態轉換到另外一個一致性的狀態,也就是說在某個時間是A,另一個時間是B。

所有事務對一個資料的讀取結果都是相同的,這是由原子性、隔離性、永續性共同保證的結果。

資料的完整性是通過其他三個特性來保證的,包括原子性、隔離性、永續性,而這三個特性,又是通過 Redo/Undo 來保證的,為了保證資料的完整性,提出來三個特性,這三個特性又是由同一個技術來實現的,所以理解 Redo/Undo 才能理解資料庫的本質。

面試官:說說資料庫事務吧

 

隔離級別

READ UNCOMMITTED 未提交讀

事務所做的修改,即使未提交,對其他事務也是可見的。事務可以讀取未提交的資料,也稱為髒讀。

也就是說能看見另一個人正在編輯的內容是什麼,毫無隱私可言。

READ COMMITTED 提交讀,也稱不可重複讀

一個事務從開始直到提交之前,所作的修改對其他事務是不可見的。也稱為不可重複讀,因為執行多次一樣的查詢,可能得到不一樣的結果。

跟未提交讀正好相反,我只有儲存了文件,你才能看得見。

REPEATABLE READ 可重複讀

同一個事務中多次讀取同樣的記錄的結果是一樣的。可能導致幻讀,在多次讀取間隙中,可能有其它事務插入新的記錄,就會出現幻讀。

面試官:說說資料庫事務吧

 

SERIALIZABLE 可序列化

最高隔離級別,強制事務序列執行,避免了幻讀的問題。

也就是事務必須一個一個排隊執行,沒有插隊的情況。

併發事務問題

髒讀:

一個事務正在對一條記錄做修改,在這個事務完成並提交前,這條記錄的資料就處於不一致狀態;這時,另一個事務也來讀取同一條記錄,如果不加控制,第二個事務讀取了這些“髒”資料,並據此做進一步的處理,就會產生未提交的資料依賴關係。這種現象被形象的叫作"髒讀"(Dirty Reads)。

所謂髒讀,就是說我沒提交別人都能看得到事務,那麼後面我刪除掉編輯的內容的話他沒看,別人還是以為我編輯了內容。

不可重複讀

一個事務在讀取某些資料後的某個時間,再次讀取以前讀過的資料,卻發現其讀出的資料已經發生了改變、或某些記錄已經被刪除了!這種現象就叫作“ 不可重複讀”(Non-Repeatable Reads)。

面試官:說說資料庫事務吧

 

幻讀

一個事務按相同的查詢條件重新讀取以前檢索過的資料,卻發現其他事務插入了滿足其查詢條件的新資料,這種現象就稱為“幻讀”(Phantom Reads)。

面試官:說說資料庫事務吧

 

「注意」

不可重複讀和幻讀看起來很像,其實是有差別的。

不可重複讀重點在於 UPDATA 和 DELETE,而幻讀的重點在於 INSERT

面試官:說說資料庫事務吧

 

MVVC多版本控制

MVCC(Multi-Version Concurrency Control),行級鎖的一個變種,在很多情況下避免了加鎖操作,開銷更低。

通過儲存資料在某個時間點的快照來實現。即是不管執行多長時間,每個事務看到的資料都是一致的。

根據事務開始時間不同,每個事務對同一張表,同一時刻看到的資料可能是不一樣的。

其實就是在高併發的訪問狀態下,對資料進行多版本控制,並通過事務的可見性來保證事務能看到自己應該看到的資料版本。

「那個多版本是如何生成的呢?」

每一次對資料庫的修改,都會在 Undo 日誌中記錄當前修改記錄的事務號及修改前資料狀態的儲存地址(即 ROLL_PTR),以便在必要的時候可以回滾到老的資料版本。

InnoDB的MVCC,是通過在每行記錄後面儲存兩個隱藏的列來實現的。兩列,一個儲存了行的建立時間,一個儲存了行的過期時間(或刪除時間),儲存的並不是實際的時間值,而是系統版本號。每開始一個事務,系統版本號都會自動遞增。事務開始時刻的系統版本號會作為事務的版本號,用來和查詢到的每行記錄的版本號進行比較。

MySQL 的 InnoDB 儲存引擎實現隔離級別的一種具體方式,用於實現「提交讀」和「可重複讀」這兩種隔離級別。而未提交讀隔離級別總是讀取最新的資料行,無需使用 MVCC。可序列化隔離級別需要對所有讀取的行都加鎖,單純使用 MVCC 無法實現。

快照讀與當前讀

在 MVCC 併發控制中,讀操作可以分為兩類: 快照讀(Snapshot Read)與當前讀 (Current Read)。

「快照讀」:讀取的是記錄的可見版本(有可能是歷史版本),不用加鎖。

「當前讀」:讀取的是記錄的最新版本,並且當前讀返回的記錄,都會加鎖,保證其他事務不會再併發修改這條記錄。

注意:MVCC 只在 Read Commited 和 Repeatable Read 兩種隔離級別下工作。

「如何區分快照讀和當前讀呢?」

快照讀:簡單的 select 操作,屬於快照讀,不需要加鎖。

當前讀:特殊的讀操作,插入/更新/刪除操作,屬於當前讀,需要加鎖。

 

 

===============================

我是Liusy,一個喜歡健身的程式設計師。

獲取更多幹貨以及最新訊息,請關注公眾號:上古偽神

如果對您有幫助,點個關注就是對我最大的支援!!!

相關文章