四類隔離級別
??SQL標準定義了4類隔離級別,包括了一些具體規則,用來限定事務內外的哪些改變是可見的,哪些是不可見的。低級別的隔離級一般支持更高的并發處理,并擁有更低的系統開銷。
Read Uncommitted(讀取未提交內容)
??在該隔離級別,所有事務都可以看到其他未提交事務的執行結果。本隔離級別很少用于實際應用,因為它的性能也不比其他級別好多少。讀取未提交的數據,也被稱之為臟讀(Dirty Read)。
舉例:
??公司發工資了,把50000元打到我的賬號上,但是該事務并未提交,而我正好去查看賬戶,發現工資已經到賬,是50000元整,非常高興??墒遣恍业氖?,領導發現發給的工資金額不對,是2000元,于是迅速回滾了事務,修改金額后,將事務提交,最后我實際的工資只有2000元,空歡喜一場。
??臟讀是兩個并發的事務,“事務A:領導發工資”、“事務B:我查詢工資賬戶”,事務B讀取了事務A尚未提交的數據。
??當隔離級別設置為Read uncommitted時,就可能出現臟讀,如何避免臟讀,請看下一個隔離級別。
Read Committed(讀取提交內容)
??這是大多數數據庫系統的默認隔離級別(但不是MySQL默認的)。它滿足了隔離的簡單定義:一個事務只能看見已經提交事務所做的改變。這種隔離級別 也支持所謂的不可重復讀(Nonrepeatable Read),因為同一事務的其他實例在該實例處理其間可能會有新的commit,所以同一select可能返回不同結果。
舉例:
??我拿著工資卡去消費,系統讀取到卡里確實有2000元,而此時老婆也正好在網上轉賬,把工資卡的2000元轉到她賬戶,并在我之前提交了事務,當我扣款時,系統檢查到工資卡已經沒有錢,扣款失敗,十分納悶,明明卡里有錢,為何…
??不可重復讀是兩個并發的事務,“事務A:消費”、“事務B:老婆網上轉賬”,事務A事先讀取了數據,事務B緊接了更新了數據,并提交了事務,而事務A再次讀取該數據時,數據已經發生了改變。
??當隔離級別設置為Read committed時,避免了臟讀,但是可能會造成不可重復讀。
Repeatable Read(可重讀)
??這是MySQL的默認事務隔離級別,它確保同一事務的多個實例在并發讀取數據時,會看到同樣的數據行。不過理論上,這會導致另一個棘手的問題:幻讀 (Phantom Read)。簡單的說,幻讀指當用戶讀取某一范圍的數據行時,另一個事務又在該范圍內插入了新行,當用戶再讀取該范圍的數據行時,會發現有新的“幻影” 行。InnoDB和Falcon存儲引擎通過多版本并發控制(MVCC,Multiversion Concurrency Control)機制解決了該問題。
舉例:
??當隔離級別設置為Repeatable read時,可以避免不可重復讀。當我拿著工資卡去消費時,一旦系統開始讀取工資卡信息(即事務開始),我老婆就不可能對該記錄進行修改,也就是不能在此時轉賬。無錫人流手術多少錢 http://mobile.chnk120.com/
??雖然Repeatable read避免了不可重復讀,但還有可能出現幻讀。例如:老婆工作在銀行部門,她時常通過銀行內部系統查看我的信用卡消費記錄。有一天,她正查詢到我當月信用卡的總消費金額(select sum(amount) from transaction where month = 本月)為80元,而我此時正好在外面吃完大餐后在收銀臺買單,消費1000元,即新增了一條1000元的消費記錄(insert transaction … ),并提交了事務,隨后老婆將我的當月信用卡消費的明細打印到A4紙上,卻發現消費總額為1080元,老婆很詫異,以為出現了幻覺,幻讀就這樣產生了。
Serializable(可串行化)
??這是最高的隔離級別,它通過強制事務排序,使之不可能相互沖突,從而解決幻讀問題。簡言之,它是在每個讀的數據行上加上共享鎖。在這個級別,可能導致大量的超時現象和鎖競爭。
隔離級別與一致性
??這四種隔離級別采取不同的鎖類型來實現,若讀取的是同一個數據的話,就容易發生問題。例如:
?? 臟讀(Drity Read):某個事務已更新一份數據,另一個事務在此時讀取了同一份數據,由于某些原因,前一個RollBack了操作,則后一個事務所讀取的數據就會是不正確的。
?? 不可重復讀(Non-repeatable read):在一個事務的兩次查詢之中數據不一致,這可能是兩次查詢過程中間插入了一個事務更新的原有的數據。
?? 幻讀(Phantom Read):在一個事務的兩次查詢中數據筆數不一致,例如有一個事務查詢了幾列(Row)數據,而另一個事務卻在此時插入了新的幾列數據,先前的事務在接下來的查詢中,就會發現有幾列數據是它先前所沒有的。
在MySQL中,實現了這四種隔離級別,分別有可能產生問題如下所示:
隔離級別 臟讀 不可重復讀 幻讀
讀未提交(Read Uncommitted) √ √ √
讀已提交(Read Committed) × √ √
可重復讀(Repeatable Read) × × √
可串行化(Serializable) × × ×
總結:
Serializable (串行化):可避免臟讀、不可重復讀、幻讀的發生。
Repeatable read (可重復讀):可避免臟讀、不可重復讀的發生。
Read committed (讀已提交):可避免臟讀的發生。
Read uncommitted (讀未提交):最低級別,任何情況都無法保證。
??以上四種隔離級別最高的是Serializable級別,最低的是Read uncommitted級別,級別越高,執行效率就越低。像Serializable這樣的級別,就是以鎖表的方式(類似于Java多線程中的鎖)使得其他的線程只能在鎖外等待,所以平時選用何種隔離級別應該根據實際情況。在MySQL數據庫中默認的隔離級別為Repeatable read (可重復讀)。
??在MySQL數據庫中,支持上面四種隔離級別,默認的為Repeatable read (可重復讀);而在Oracle數據庫中,只支持Serializable (串行化)級別和Read committed (讀已提交)這兩種級別,其中默認的為Read committed級別。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。