數據庫常用的事務隔離級別都有哪些?都是什麼原理?

什麼是事務隔離?

任何支持事務的數據庫,都必須具備四個特性,分別是:原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability),也就是我們常說的事務ACID,這樣才能保證事務((Transaction)中數據的正確性。

而事務的隔離性就是指,多個併發的事務同時訪問一個數據庫時,一個事務不應該被另一個事務所幹擾,每個併發的事務間要相互進行隔離。

如果沒有事務隔離,會出現什麼樣的情況呢?

假設我們現在有這樣一張表(T),裏面記錄了很多牛人的名字,我們不進行事務的隔離看看會發生什麼呢?

第一天,事務A訪問了數據庫,它幹了一件事情,往數據庫里加上了新來的牛人的名字,但是沒有提交事務。

insert into T values (4, '牛D');

這時,來了另一個事務B,他要查詢所有牛人的名字。

select Name from T;

這時,如果沒有事務之間沒有有效隔離,那麼事務B返回的結果中就會出現“牛D”的名字。這就是“髒讀(dirty read)”。

第二天,事務A訪問了數據庫,他要查看ID是1的牛人的名字,於是執行了

select Name from T where ID = 1;

這時,事務B來了,因爲ID是1的牛人改名字了,所以要更新一下,然後提交了事務。

update T set Name = '不牛' where ID = 1;

接着,事務A還想再看看ID是1的牛人的名字,於是又執行了

select Name from T where ID = 1;

結果,兩次讀出來的ID是1的牛人名字竟然不相同,這就是不可重複讀(unrepeatable read)。

第三天,事務A訪問了數據庫,他想要看看數據庫的牛人都有哪些,於是執行了

select * from T;

這時候,事務B來了,往數據庫加入了一個新的牛人。

insert into T values(4, '牛D');

這時候,事務A忘了剛纔的牛人都有哪些了,於是又執行了。

select * from T;

結果,第一次有三個牛人,第二次有四個牛人。

相信這個時候事務A就蒙了,剛纔發生了什麼?這種情況就叫“幻讀(phantom problem)”。

爲了防止出現髒讀、不可重複讀、幻讀等情況,我們就需要根據我們的實際需求來設置數據庫的隔離級別。

數據庫都有哪些隔離級別呢?

一般的數據庫,都包括以下四種隔離級別:

讀未提交(Read Uncommitted)讀提交(Read Committed)可重複讀(Repeated Read)串行化(Serializable)如何使用這些隔離級別,那就需要根據業務的實際情況來進行判斷了。

我們接下來就看看這四個隔離級別的具體情況

讀未提交(Read Uncommitted)

讀未提交,顧名思義,就是可以讀到未提交的內容。

因此,在這種隔離級別下,查詢是不會加鎖的,也由於查詢的不加鎖,所以這種隔離級別的一致性是最差的,可能會產生“髒讀”、“不可重複讀”、“幻讀”。

如無特殊情況,基本是不會使用這種隔離級別的。

讀提交(Read Committed)

讀提交,顧名思義,就是隻能讀到已經提交了的內容。

這是各種系統中最常用的一種隔離級別,也是SQL Server和Oracle的默認隔離級別。這種隔離級別能夠有效的避免髒讀,但除非在查詢中顯示的加鎖,如:

select * from T where ID=2 lock in share mode;

select * from T where ID=2 for update;

不然,普通的查詢是不會加鎖的。

那爲什麼“讀提交”同“讀未提交”一樣,都沒有查詢加鎖,但是卻能夠避免髒讀呢?

這就要說道另一個機制“快照(snapshot)”,而這種既能保證一致性又不加鎖的讀也被稱爲“快照讀(Snapshot Read)”

假設沒有“快照讀”,那麼當一個更新的事務沒有提交時,另一個對更新數據進行查詢的事務會因爲無法查詢而被阻塞,這種情況下,併發能力就相當的差。

而“快照讀”就可以完成高併發的查詢,不過,“讀提交”只能避免“髒讀”,並不能避免“不可重複讀”和“幻讀”。

可重複讀(Repeated Read)

可重複讀,顧名思義,就是專門針對“不可重複讀”這種情況而制定的隔離級別,自然,它就可以有效的避免“不可重複讀”。而它也是MySql的默認隔離級別。

在這個級別下,普通的查詢同樣是使用的“快照讀”,但是,和“讀提交”不同的是,當事務啓動時,就不允許進行“修改操作(Update)”了,而“不可重複讀”恰恰是因爲兩次讀取之間進行了數據的修改,因此,“可重複讀”能夠有效的避免“不可重複讀”,但卻避免不了“幻讀”,因爲幻讀是由於“插入或者刪除操作(Insert or Delete)”而產生的。

串行化(Serializable)

這是數據庫最高的隔離級別,這種級別下,事務“串行化順序執行”,也就是一個一個排隊執行。

這種級別下,“髒讀”、“不可重複讀”、“幻讀”都可以被避免,但是執行效率奇差,性能開銷也最大,所以基本沒人會用。

總結一下

爲什麼會出現“髒讀”?因爲沒有“select”操作沒有規矩。

爲什麼會出現“不可重複讀”?因爲“update”操作沒有規矩。

爲什麼會出現“幻讀”?因爲“insert”和“delete”操作沒有規矩。

“讀未提(Read Uncommitted)”能預防啥?啥都預防不了。

“讀提交(Read Committed)”能預防啥?使用“快照讀(Snapshot Read)”,避免“髒讀”,但是可能出現“不可重複讀”和“幻讀”。

“可重複讀(Repeated Red)”能預防啥?使用“快照讀(Snapshot Read)”,鎖住被讀取記錄,避免出現“髒讀”、“不可重複讀”,但是可能出現“幻讀”。

“串行化(Serializable)”能預防啥?排排坐,吃果果,有效避免“髒讀”、“不可重複讀”、“幻讀”,不過效果誰用誰知道。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章