在SQL標準中定義了四種隔離級別,每種隔離級別都規定了一個事務中所做的修改,哪些事務內和事務間是可見的,哪些是不可見的。較低級別的隔離通常可以執行更高的併發,系統的開銷也更低。
***每種存儲引擎實現的隔離級別不盡相同,後面會簡單舉例介紹***
注意:我們討論隔離級別的場景,主要是在多個事務併發的情況下,因此,接下來的講解都圍繞事務併發。(併發的概念自己去查)
髒讀:
是兩個事務在一個連接裏才行:即同連接中事務T1修改數據,事務T2讀取數據;mysql各個進程之間在不提交的情況下是不會出現髒讀的。一個事務讀到另外一個
事務還沒有提交的數據叫做髒讀,不意味着在數據庫裏一個事務一定會讀到另外一個事務還沒有提交的數據(有點繞)。
不可重複讀:
啓動A事務——>A查詢表——>啓動B事務——>B查詢表——>B修改表——B事務提交(不會出錯哦,鬱悶中。。。)——>A查詢表(數據會保證和上一次A查詢的數據一致)——>A事務修改表(不出錯)——>A事務提交(事務提交成功,不出錯)
這樣勢必造成一個結果就是B修改的數據對於A是透明的,就好像不存在,而且最終會覆蓋B的結果
幻讀:
解決了不重複讀,保證了同一個事務裏,查詢的結果都是事務開始時的狀態(一致性)。但是,如果另一個事務同時提交了新數據,本事務再更新時,就會“驚奇的”發現了這些新數據,貌似之前讀到的數據是“鬼影”一樣的幻覺。
隔離級別的類型如下:
2.2.1 READ UNCOMMITED(未提交讀)
(1)在READ UNCOMMITED級別,事務中的修改,即使沒有提交,對其他事務也都是可見的。
(2)事務是可以讀取未提交的數據,這也被稱爲髒讀(Dirty Read)。允許髒讀,但不允許更新丟失。
(3)這個級別會導致很多的問題:髒讀、幻讀、不可重複讀等。
案例分析:
公司發工資了,領導把5000元打到隔壁老王的賬號上,但是該事務並未提交,而隔壁老王正好去查看賬戶,發現工資已經到賬,是5000元整,非常高興。可是不幸的是,領導發現發給隔壁老王的工資金額不對,是2000元,於是迅速回滾了事務,修改金額後,將事務提交,最後隔壁老王實際的工資只有2000元,隔壁老王空歡喜一場!!!
出現上述情況,即我們所說的髒讀,兩個併發的事務,“事務A:給隔壁老王發工資”、“事務B:隔壁老王查詢工資賬戶”,事務B讀取了事務A尚未提交的數據。
從性能上來說,READ UNCOMMIT不會比其他的級別好太多,但卻缺乏其他級別很多好處,除非真的有必要的理由,在實際應用中一般很少使用。
當隔離級別設置爲Read uncommitted時,就可能出現髒讀,如何避免髒讀,請看下一個隔離級別
2.2.2 READ COMMIT(提交讀)
簡單定義:一個事務開始時,只能“看見”已經提交的事務所做的修改。【一個事務從開始直到提交之前,所做的任何修改對其他事務所都是不可見的】
(1)大多數數據庫系統默認的隔離級別都是READ COMMIT(如:SQL Server,Oracle),但是MySQL不是。
(2)這個級別有時候也叫做不可重複讀(norepeatable read),因爲兩次執行同樣的查詢,可能會導致不一樣的結果。
這裏舉例說明:
隔壁老王拿着工資卡去消費,系統讀取到卡里確實有2000元,而此時她的老婆也正好在網上轉賬,把隔壁老王工資卡的2000元轉到另一賬戶,並在隔壁老王之前提交了事務,當隔壁老王扣款時,系統檢查到隔壁老王的工資卡已經沒有錢,扣款失敗,隔壁老王十分納悶,明明卡里有錢,爲何......
出現上述情況,即我們所說的不可重複讀,兩個併發的事務,“事務A:隔壁老王消費”、“事務B:隔壁老王的老婆網上轉賬”,事務A事先讀取了數據,事務B緊接了更新了數據,並提交了事務,而事務A再次讀取該數據時,數據已經發生了改變。
當隔離級別設置爲Read committed時,避免了髒讀,但是可能會造成不可重複讀。解決此問題,請看下一個級別。
2.2.3 REPEATABLE READ(可重複讀)
(1) 解決了髒讀問題,保證了在同一個事物中多次讀取同樣的記錄的結果是一致的。
(2) MySQL默認的事務隔離級別。
(3)【理論上】還是無法解決幻讀的問題。
---幻讀(Phantom Read):指的是當某個事務還在讀取某個範圍內的記錄時,另外一個事務又在該範圍內插入了新的記錄,當之前的事務再次讀取該範圍的記錄時,會產生幻行(Phantom Row)。
InnoDB和XtraDB存儲引擎通過多版本併發控制(MVCC,Multiversion Concurrency Control)解決了幻讀的問題
案例分析:
隔壁老王的老婆工作在銀行部門,她時常通過銀行內部系統查看隔壁老王的信用卡消費記錄。有一天,她正在查詢到隔壁老王當月信用卡的總消費金額(select sum(amount) from transaction where month = 本月)爲80元,而隔壁老王此時正好在外面胡吃海塞後在收銀臺買單,消費1000元,即新增了一條1000元的消費記錄(insert transaction ... ),並提交了事務,隨後隔壁老王的老婆將隔壁老王當月信用卡消費的明細打印到A4紙上,卻發現消費總額爲1080元,隔壁老王的老婆很詫異,以爲出現了幻覺,幻讀就這樣產生了。
上面的情況,即爲出現的幻讀情況。此級別解決了髒讀問題,解決解決幻讀問題,請看下面的級別。
2.2.4 SERIALIZABLE(可串行化)
可串行化:在讀取的每一行數據上加鎖,保持序列化
(1) 最高的隔離級別。
(2) 通過強制事務串行執行,避免了前面說的幻讀問題。
(3) 代價也花費最高,性能很低,加鎖耗時、鎖爭問題。
(4) 一般很少使用,在該級別下,事務順序執行,不僅可以避免髒讀、不可重複讀,還避免了幻像讀。
(5) 只有在非常需要確保數據的一致性而且可以接受沒有併發的情況,才考慮採用該級別。
事務的隔離級別:
READ UNCOMMIT:髒讀,不可重複度,幻讀
READ COMMIT:不可重複度,幻讀
REPEATABLE READ:幻讀 (InnoDB和XtraDB存儲引擎通過多版本併發控制(mvcc,Multiversion Concurrency Control)解決幻讀問題)
SERIALIZABLE:加鎖讀