數據庫事務的四種隔離級別

spring(數據庫)事務隔離級別分爲四種(級別遞減):

1、Serializable (串行化)

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

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

2、REPEATABLE READ(可重複讀)

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

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

3、READ COMMITTED (讀提交)

讀提交,顧名思義,就是隻能讀到已經提交了的內容。這是各種系統中最常用的一種隔離級別,也是SQL Server和Oracle的默認隔離級別,保證了一個事務不會讀到另一個並行事務已修改但未提交的數據,避免了“髒讀取”,但不能避免“幻讀”和“不可重複讀取”。該級別適用於大多數系統。這裏多說點:那爲什麼“讀提交”同“讀未提交”一樣,都沒有查詢加鎖,但是卻能夠避免髒讀呢?

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

假設沒有“快照讀”,那麼當一個更新的事務沒有提交時,另一個對更新數據進行查詢的事務會因爲無法查詢而被阻塞,這種情況下,併發能力就相當的差。而“快照讀”就可以完成高併發的查詢,不過,“讀提交”只能避免“髒讀”,並不能避免“不可重複讀”和“幻讀”。

4、Read Uncommitted(讀未提交)

讀未提交,顧名思義,就是可以讀到未提交的內容。因此,在這種隔離級別下,查詢是不會加鎖的,也由於查詢的不加鎖,所以這種隔離級別的一致性是最差的,可能會產生“髒讀”、“不可重複讀”、“幻讀”。如無特殊情況,基本是不會使用這種隔離級別的。

 

髒讀、不可重複讀、幻讀:

也許有很多讀者會對上述隔離級別中提及到的 髒讀、不可重複讀、幻讀 的理解有點吃力,我在這裏嘗試使用通俗的方式來解釋這三種語義:

髒讀:所謂的髒讀,其實就是讀到了別的事務回滾前的髒數據。比如事務B執行過程中修改了數據X,在未提交前,事務A讀取了X,而事務B卻回滾了,這樣事務A就形成了髒讀。

也就是說,當前事務讀到的數據是別的事務想要修改成爲的但是沒有修改成功的數據。

不可重複讀:事務A首先讀取了一條數據,然後執行邏輯的時候,事務B將這條數據改變了,然後事務A再次讀取的時候,發現數據不匹配了,就是所謂的不可重複讀了。

也就是說,當前事務先進行了一次數據讀取,然後再次讀取到的數據是別的事務修改成功的數據,導致兩次讀取到的數據不匹配,也就照應了不可重複讀的語義。

幻讀:事務A首先根據條件索引得到N條數據,然後事務B改變了這N條數據之外的M條或者增添了M條符合事務A搜索條件的數據,導致事務A再次搜索發現有N+M條數據了,就產生了幻讀。

也就是說,當前事務讀第一次取到的數據比後來讀取到數據條目少。

 

不可重複讀和幻讀比較:

兩者有些相似,但是前者針對的是update或delete,後者針對的insert。

 

總結一下:

Q1: 爲什麼會出現“髒讀”?

A1: 因爲沒有“select”操作沒有規矩。

Q2: 爲什麼會出現“不可重複讀”?

A2: 因爲“update”操作沒有規矩。

Q3: 爲什麼會出現“幻讀”?

A3: 因爲“insert”和“delete”操作沒有規矩。

Q4: “讀未提(Read Uncommitted)”能預防啥?

Q4: 啥都預防不了。

Q5: “讀提交(Read Committed)”能預防啥?

A5: 使用“快照讀(Snapshot Read)”,避免“髒讀”,但是可能出現“不可重複讀”和“幻讀”。

Q6: “可重複讀(Repeated Red)”能預防啥?

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

Q7: “串行化(Serializable)”能預防啥?

A7: 排排坐,吃果果,有效避免“髒讀”、“不可重複讀”、“幻讀”,不過效果誰用誰知道。

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