淺顯易懂說事務(wù)隔離級別

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

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

事務(wù)隔離級別

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

  • 讀未提交(read uncommitted)。即一個事務(wù)在還沒有提交時,其所作的變更可以被其他事務(wù)看到。

  • 讀提交(read committed)。一個事務(wù)被提交以后其所作的更改才可以被其他事務(wù)看到。

  • 可重復(fù)讀(repeatable read)。一個事務(wù)在執(zhí)行過程中看到的數(shù)據(jù)只和開始時的數(shù)據(jù)一樣。

  • 串行化(serializable)。所謂的串行,顧名思義就相當(dāng)于排隊,也就是事務(wù)的執(zhí)行必須等待前一個事務(wù)的所有操作完結(jié)之后才可以執(zhí)行。其本質(zhì)是給表記錄加“寫鎖”或者是“讀鎖”。

其中,數(shù)據(jù)庫一般使用讀提交和可重復(fù)讀這兩種類型的隔離級別比較多。像Oracle數(shù)據(jù)庫默認(rèn)使用的隔離級別是讀提交,而MySQL默認(rèn)使用的隔離級別是可重復(fù)讀。當(dāng)然,我們也可以通過命令來查看MySQL的隔離級別。使用以下命令:

show variables like 'tx_isolation';
淺顯易懂說事務(wù)隔離級別

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

show variables like 'transaction_isolation';

當(dāng)然,如果你想修改默認(rèn)的隔離級別的話,可以運行如下命令:

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

其中g(shù)lobal表示的是全局的,而session表示僅僅當(dāng)前的窗口修改事務(wù)的隔離級別。

牛刀小試

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

淺顯易懂說事務(wù)隔離級別

接下來,有兩個事務(wù),其執(zhí)行過程如下:

淺顯易懂說事務(wù)隔離級別

那么,對于不同的事務(wù)的隔離級別,其得到的V1、V2、V3的值分別是多少呢?

  • 讀未提交。V1、V2、V3的值都為2。

  • 讀提交。V1值為1。因為提交之后才能看到其他事務(wù)的值,所以B提交以后,A事務(wù)可以看到其修改后的值,所以V2、V3的值為2。

  • 可重復(fù)讀。由于事務(wù)在執(zhí)行期間所有的值都是一致的,所以的V1、V2的值都為1,后來事務(wù)提交了,所以可以看到其他事務(wù)的值,其值為V3。

  • 串行化。事務(wù) B 執(zhí)行“將 1 改成 2”的時候,會被鎖住。直到事務(wù)A提交以后,事務(wù)B才可以繼續(xù)執(zhí)行,所以對于A來說,V1、V2的值為1,V2的值為2。

那么,執(zhí)行事務(wù)的過程中,MySQL是怎么實現(xiàn)的呢?在開始的時候,數(shù)據(jù)庫會創(chuàng)建一個視圖,訪問的時候以視圖的邏輯結(jié)果為準(zhǔn)。在“可重復(fù)讀”隔離級別下,這個視圖是在事務(wù)啟動時創(chuàng)建的,整個事務(wù)存在期間都用這個視圖。在“讀提交”隔離級別下,這個視圖是在每個 SQL 語句開始執(zhí)行的時候創(chuàng)建的。這里需要注意的是,“讀未提交”隔離級別下直接返回記錄上的最新值,沒有視圖概念;而“串行化”隔離級別下直接用加鎖的方式來避免并行訪問。

實現(xiàn)原理

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

假設(shè)一個值從 4 被按順序改成了 5、6、7,那么在回滾日志里面就會出現(xiàn)類似下面的記錄。

淺顯易懂說事務(wù)隔離級別

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容