淺顯易懂說事務隔離級別

淺顯易懂說事務隔離級別

MySQL

作為程序員,想必經常和MySQL數據庫打交道的道友們應該很熟悉事務。事務最被我們記住的那就是一致性了,就是整個流程下來,要麼全部成功,要麼全部失敗。最典型的例子就是銀行轉賬問題,例如我賬戶有100塊,全部轉賬個B同學,那麼程序上需要做的操作就是現在我的賬戶里扣掉100塊,然後再給B同學打100塊,整個過程下來必須是一致性的,要麼整個流程都成功,要麼就全部失敗,不能說扣了我100塊,然後因為其他原因致使轉賬給B同學的100塊沒有了,這樣的話銀行就得亂套了。當然,事務只可用於Innodb類型的表。

提到事務的特性,想必大家的第一反應想到的就是事務的四大特性:即原子性、一致性、隔離性、持久性。今天在這裡我們要介紹的是事務的隔離性。

事務隔離級別

想想如果在同一時間有多個人在同時操作多個事務,如果事務沒有隔離性就會帶來數據的髒讀、幻讀和不可重複讀的問題。當然,事物都是具有兩面性的,隔離的程度越高,相應的程序的執行效率就會越慢(鎖表等行為帶來的鎖等待)。所以我們需要在隔離級別和效率上尋求平衡點。那麼,事務的隔離級別有哪些呢?MySQL主要提供了以下的四種隔離級別:

  • 讀未提交(read uncommitted)。即一個事務在還沒有提交時,其所作的變更可以被其他事務看到。
  • 讀提交(read committed)。一個事務被提交以後其所作的更改才可以被其他事務看到。
  • 可重複讀(repeatable read)。一個事務在執行過程中看到的數據只和開始時的數據一樣。
  • 串行化(serializable)。所謂的串行,顧名思義就相當於排隊,也就是事務的執行必須等待前一個事務的所有操作完結之後才可以執行。其本質是給表記錄加“寫鎖”或者是“讀鎖”。

其中,數據庫一般使用讀提交和可重複讀這兩種類型的隔離級別比較多。像Oracle數據庫默認使用的隔離級別是讀提交,而MySQL默認使用的隔離級別是可重複讀。當然,我們也可以通過命令來查看MySQL的隔離級別。使用以下命令:

show variables like 'tx_isolation';

得到的結果如下:

淺顯易懂說事務隔離級別

MySQL默認隔離級別

注:對於MySQL版本大於5.7的,該運行以下命令:

show variables like 'transaction_isolation';

當然,如果你想修改默認的隔離級別的話,可以運行如下命令:

set [ global | session ] transaction isolation level Read uncommitted | Read committed | Repeatable | Serializable;

其中global表示的是全局的,而session表示僅僅當前的窗口修改事務的隔離級別。

牛刀小試

接下來我們實際操作一下,看情況如何。首先我們先建一張名為test的表,其結果如下

淺顯易懂說事務隔離級別

數據

接下來,有兩個事務,其執行過程如下:

淺顯易懂說事務隔離級別

事務流程

那麼,對於不同的事務的隔離級別,其得到的V1、V2、V3的值分別是多少呢?

  • 讀未提交。V1、V2、V3的值都為2。
  • 讀提交。V1值為1。因為提交之後才能看到其他事務的值,所以B提交以後,A事務可以看到其修改後的值,所以V2、V3的值為2。
  • 可重複讀。由於事務在執行期間所有的值都是一致的,所以的V1、V2的值都為1,後來事務提交了,所以可以看到其他事務的值,其值為V3。
  • 串行化。事務 B 執行“將 1 改成 2”的時候,會被鎖住。直到事務A提交以後,事務B才可以繼續執行,所以對於A來說,V1、V2的值為1,V2的值為2。

那麼,執行事務的過程中,MySQL是怎麼實現的呢?在開始的時候,數據庫會創建一個視圖,訪問的時候以視圖的邏輯結果為準。在“可重複讀”隔離級別下,這個視圖是在事務啟動時創建的,整個事務存在期間都用這個視圖。在“讀提交”隔離級別下,這個視圖是在每個 SQL 語句開始執行的時候創建的。這裡需要注意的是,“讀未提交”隔離級別下直接返回記錄上的最新值,沒有視圖概念;而“串行化”隔離級別下直接用加鎖的方式來避免並行訪問。

實現原理

在此之前,有必要介紹一下MVCC,也就是多版本控制,就如我麼經常使用的svn或者是git,其也算是MVCC工具。網上看到大量的文章講到MVCC都是說給沒一行增加兩個隱藏的字段分別表示行的創建時間以及過期時間,它們存儲的並不是時間,而是事務版本號。也就是說MySQL在每條記錄更新的時候都會記錄一條回滾操作。記錄上的最新值通過回滾操作都可以得到前一條被更改前的值。

假設一個值從 4 被按順序改成了 5、6、7,那麼在回滾日誌裡面就會出現類似下面的記錄。

淺顯易懂說事務隔離級別

mysql回滾記錄

當前值是 7,但是在查詢這條記錄的時候,不同時刻啟動的事務會有不同的 read-view。如圖中看到的,在視圖 A、B、C 裡面,這一個記錄的值分別是 4、5、6,同一條記錄在系統中可以存在多個版本,就是數據庫的多版本併發控制(MVCC)。對於 read-view A,要得到 4,就必須將當前值依次執行圖中所有的回滾操作得到。

今天的MySQL事務隔離就講到這裡了。喜歡的可以關注我或者是給我點贊哦。祝大家生活愉快。


分享到:


相關文章: