資料庫事務的隔離級別有4種,由低到高分別為read uncommitted 、read committed 、repeatable read 、serializable 。而且,在事務的併發操作中可能會出現髒讀,不可重複讀,幻讀。下面通過事例一一闡述它們的概念與聯絡。
髒讀、不可重複讀、幻象讀概念說明:
髒讀:指當乙個事務正在訪問資料,並且對資料進行了修改,而這種資料還沒有提交到資料庫中,這時,另外乙個事務也訪問這個資料,然後使用了這個資料。因為這個資料還沒有提交那麼另外乙個事務讀取到的這個資料我們稱之為髒資料。依據髒資料所做的操作肯能是不正確的。
不可重複讀:指在乙個事務內,多次讀同一資料。在這個事務還沒有執行結束,另外乙個事務也訪問該同一資料,那麼在第乙個事務中的兩次讀取資料之間,由於第二個事務的修改第乙個事務兩次讀到的資料可能是不一樣的,這樣就發生了在乙個事物內兩次連續讀到的資料是不一樣的,這種情況被稱為是不可重複讀。
幻象讀:乙個事務先後讀取乙個範圍的記錄,但兩次讀取的紀錄數不同,我們稱之為幻象讀(兩次執行同一條 select 語句會出現不同的結果,第二次讀會增加一資料行,並沒有說這兩次執行是在同乙個事務中)
讀未提交 (read uncommitted)
讀未提交,顧名思義,就是乙個事務可以讀取另乙個未提交事務的資料。
事例:老闆要給程式設計師發工資,程式設計師的工資是3.6萬/月。但是發工資時老闆不小心按錯了數字,按成3.9萬/月,該錢已經打到程式設計師的戶口,但是事務還沒有提交,就在這時,程式設計師去檢視自己這個月的工資,發現比往常多了3千元,以為漲工資了非常高興。但是老闆及時發現了不對,馬上回滾差點就提交了的事務,將數字改成3.6萬再提交。
分析:實際程式設計師這個月的工資還是3.6萬,但是程式設計師看到的是3.9萬。他看到的是老闆還沒提交事務時的資料。這就是髒讀。因此,在這種隔離級別下,查詢是不會加鎖的,也由於查詢的不加鎖,所以這種隔離級別的一致性是最差的,可能會產生「髒讀」、「不可重複讀」、「幻讀」。如無特殊情況,基本是不會使用這種隔離級別的。
那怎麼解決髒讀呢?read committed!讀提交,能解決髒讀問題。
讀提交(read committed)
讀提交,顧名思義,就是只能讀到已經提交了的內容
事例:程式設計師拿著信用卡去享受生活(卡里當然是只有3.6萬),當他埋單時(程式設計師事務開啟),收費系統事先檢測到他的卡里有3.6萬,就在這個時候!!程式設計師的妻子要把錢全部轉出充當家用,並提交。當收費系統準備扣款時,再檢測卡里的金額,發現已經沒錢了(第二次檢測金額當然要等待妻子轉出金額事務提交完)。程式設計師就會很鬱悶,明明卡里是有錢的…
分析:這就是讀提交,若有事務對資料進行更新(update)操作時,讀操作事務要等待這個更新操作事務提交後才能讀取資料,可以解決髒讀問題。但在這個事例中,出現了乙個事務範圍內兩個相同的查詢卻返回了不同資料,這就是不可重複讀。
這是各種系統中最常用的一種隔離級別,也是sql server和oracle的預設隔離級別。這種隔離級別能夠有效的避免髒讀,但除非在查詢中顯示的加鎖,如:
select * from t where id=2 lock in share mode;select * from t where id=2 for update;
不然,普通的查詢是不會加鎖的。
那為什麼「讀提交」同「讀未提交」一樣,都沒有查詢加鎖,但是卻能夠避免髒讀呢?
這就要說道另乙個機制「快照(snapshot)」,而這種既能保證一致性又不加鎖的讀也被稱為「快照讀(snapshot read)」
假設沒有「快照讀」,那麼當乙個更新的事務沒有提交時,另乙個對更新資料進行查詢的事務會因為無法查詢而被阻塞(因為上了x鎖,即寫鎖,所以不能得到s鎖,即讀鎖),這種情況下,併發能力就相當的差。而「快照讀」就可以完成高併發的查詢,不過,「讀提交」只能避免「髒讀」,並不能避免「不可重複讀」和「幻讀」。
那怎麼解決可能的不可重複讀問題?repeatable read !
可重複讀(repeated read)
可重複讀,顧名思義,就是專門針對「不可重複讀」這種情況而制定的隔離級別,自然,它就可以有效的避免「不可重複讀」。而它也是mysql的預設隔離級別。
事例:程式設計師拿著信用卡去享受生活(卡里當然是只有3.6萬),當他埋單時(事務開啟,不允許其他事務的update修改操作),收費系統事先檢測到他的卡里有3.6萬。這個時候他的妻子不能轉出金額了。接下來收費系統就可以扣款了。
分析:重複讀可以解決不可重複讀問題。寫到這裡,應該明白的一點就是,不可重複讀對應的是修改,即update操作。但是可能還會有幻讀問題。因為幻讀問題對應的是插入insert操作,而不是update操作。
什麼時候會出現幻讀?
事例:程式設計師某一天去消費,花了2千元,然後他的妻子去檢視他今天的消費記錄(全表掃瞄fts,妻子事務開啟),看到確實是花了2千元,就在這個時候,程式設計師花了1萬買了一部電腦,即新增insert了一條消費記錄,並提交。當妻子列印程式設計師的消費記錄清單時(妻子事務提交),發現花了1.2萬元,似乎出現了幻覺,這就是幻讀。
在這個級別下,普通的查詢同樣是使用的「快照讀」,但是,和「讀提交」不同的是,當事務啟動時,就不允許進行「修改操作(update)」了,而「不可重複讀」恰恰是因為兩次讀取之間進行了資料的修改,因此,「可重複讀」能夠有效的避免「不可重複讀」,但卻避免不了「幻讀」,因為幻讀是由於「插入或者刪除操作(insert or delete)」而產生的。
那怎麼解決幻讀問題?serializable!
序列化serializable
這是資料庫最高的隔離級別,這種級別下,事務「序列化順序執行」,也就是乙個乙個排隊執行。這種級別下,「髒讀」、「不可重複讀」、「幻讀」都可以被避免,但是執行效率奇差,效能開銷也最大,所以基本沒人會用。
值得一提的是:大多數資料庫預設的事務隔離級別是read committed,比如sql server , oracle。mysql的預設隔離級別是repeatable read。
mysql如何解決幻讀問題?
(1)什麼是幻讀
在一次事務裡面,多次查詢之後,結果集的個數不一致的情況叫做幻讀。而多出來或者少的哪一行被叫做 幻行
(2)幻讀產生的原因
行鎖只能鎖住行,即使把所有的行記錄都上鎖,也阻止不了新插入的記錄。
(3)如何解決幻讀?
備註:什麼是快照讀、當前讀
- 快照讀, 讀取專門的快照 (對於rc,快照(readview)會在每個語句中建立。對於rr,快照是在事務啟動時建立的)```簡單的select操作即可(不需要加鎖,如: select ... lock in share mode, select ... for update)
```針對的也是select操作
- 當前讀, 讀取最新版本的記錄, 沒有快照。 在innodb中,當前讀取根本不會建立任何快照。
```select ... lock in share mode
select ... for update
insert
update
delete
針對如下操作, 會讓如下操作阻塞:
```insert
update
delete
```- 在rr(可重複讀)級別下, 快照讀是通過mvvc(多版本控制)和undo log來實現的,
當前讀是通過手動加record lock(記錄鎖)和gap lock(間隙鎖)來實現的。所以從上面的顯示來看,如果需要實時顯示資料,還是需要通過加鎖來實現。這個時候會使用next-key技術來實現。
總結一下:
出處:
資料庫事務隔離級別
資料庫事務的隔離級別有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...