衆所周知MySQL從5.5.8開始,Innodb就是默認的存儲引擎,Innodb最大的特色是:支持事務、支持行級鎖。數據庫
既然支持事務,那麼就會有處理併發事務帶來的問題:更新丟失、髒讀、不可重複讀、幻讀;相應的爲了解決這四個問題,併發
就產生了事務隔離級別:未提交讀(Read uncommitted),已提交讀(Read committed),可重複讀(Repeatable read),可序列化(Serializable)。學習
以前在看事務隔離級別的時候,基本是隻知其一;不知其二。再次碰到,仍是漿糊,因此這裏打算完全搞明白、清楚,也好後續的學習。spa
一、概念說明: blog
更新丟失:最後的更新覆蓋了其餘事務以前的更新,而事務之間並不知道,發生更新丟失。更新丟失,能夠徹底避免,應用對訪問的數據加鎖便可。事務
髒讀:(針對未提交的數據)一個事務在更新一條記錄,未提交前,第二個事務讀到了第一個事務更新後的記錄,那麼第二個事務就讀到了髒數據,會產生對第一個未提交string
數據的依賴。一旦第一個事務回滾,那麼第二個事務讀到的數據,將是錯誤的髒數據。it
不可重複讀:(讀取數據自己的對比)一個事務在讀取某些數據後的一段時間後,再次讀取這個數據,發現其讀取出來的數據內容已經發生了改變,就是不可重複讀。table
幻讀:(讀取結果集條數的對比)一個事務按相同的查詢條件查詢以前檢索過的數據,確發現檢索出來的結果集條數變多或者減小(由其餘事務插入、刪除的),相似產生幻覺。class
二、不可重複讀和幻讀的區別:
不可重複讀
重點是修改:一樣的條件下,你讀取過的數據,再次讀取發現值不同了。
例子:(只是爲了說明區別,沒有事務隔離級別約束)
事務1:Jack讀取本身的工資爲1000,事務並無結束:
select salary from employee empId ="Jack";
事務2:財務人員修改了Jack的工資爲2000,並提交事務(事務1不知道):
update employee set salary = 2000;
commit;
在事務1中,再次讀取Jack的工資時,工資變爲2000
select salary from employee empId ="Jack";
在一個事務中先後兩次讀取的結果值並不一致,致使了不可重讀讀
幻讀
重點在於新增或者刪除(數據條數的變化):一樣條件下,第一次和第二次讀出來的記錄條數不同。
例子:
目前工資爲1000的員工有10人。
事務1:讀取全部工資爲1000的員工,事務進行中
select count(*) from employee where salary = 1000;
共讀取到10條記錄。
事務2:同時插入一條新的員工記錄,工資也爲1000
insert into employee(empId, salary) values('Tom', 1000);
commit;
事務1:再次讀取全部工資爲1000的員工
select count(*) from employee where salary = 1000;
共讀取到了11條記錄,這樣就像產生了幻讀。
併發處理帶來的問題中,更新丟失能夠徹底避免,由應用對數據加鎖便可。髒讀、不可重讀度、幻讀,其實都是數據庫的一致性問題,必須由必定的事務隔離機制來解決。
其中一種方法是:不用加鎖,經過必定的機制生成一個數據請求時間點的一致性快照,並用這個快照來提供一個界別的一致性讀取。從用戶的角度看,好像是數據庫提偶拱了
統一數據的多個版本。這種技術叫作:數據庫多版本併發控制,MVCC 多版本數據庫。
事務隔離的本質是使事務在必定程度上串行化執行,顯然和併發機制是矛盾的。數據庫的事務隔離越嚴格,併發負做用越小,代價越高(影響併發訪問了唄)。
爲了解決隔離和並大的矛盾,IOS SQL92規定了4個隔離級別。(隔離==串行)
MySQL 默認的級別是:Repeatable read 可重複讀。