什麼是事務隔離?
任何支援事務的資料庫,都必須具備四個特性,分別是:原子性(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)」能預防啥?排排坐,吃果果,有效避免「髒讀」、「不可重複讀」、「幻讀」,不過效果誰用誰知道。
資料庫事務隔離級別
資料庫事務的隔離級別有4個,由低到高依次為read uncommitted read committed repeatable read serializable,這四個級別可以逐個解決髒讀 不可重複讀 幻讀這幾類問題。可能出現 不會出現 髒讀不可重複讀 幻讀read uncommitted rea...
資料庫事務隔離級別
資料庫事務的隔離級別有4個,由低到高依次為read uncommitted read committed repeatable read serializable,這四個級別可以逐個解決髒讀 不可重複讀 幻讀這幾類問題。可能出現 不會出現 髒讀不可重複讀 幻讀read uncommitted rea...
資料庫事務隔離級別
資料庫事務的隔離級別有4個,由低到高依次為read uncommitted read committed repeatable read serializable 這四個級別可以逐個解決髒讀 不可重複讀 幻讀 這幾類問題。可能出現 不會出現 髒讀不可重複讀 幻讀read uncommitted re...