1. read uncommitted,讀未提交。事務A能讀取到事務B已修改但未提交的數據。髒讀
2. read committed,讀已提交。事務A只能讀取到事務B已經提交的數據,但由於事務讀取到的是它每次SELECT前的數據快照,因此同一事務多次SELECT的結果可能不同。不可重復讀。大多數關系數據庫(如Oracle)的默認隔離等級
3. repeatable read,可重復讀。事務A只能讀取到事務B已經提交的數據,且同一事務每次讀取到的數據均相同。這是因為事務讀取到的是事務開始時的數據快照,同一事務中只有一份且保持不變直到事務結束。但是,由於數據快照生成於事務開始時,若不同事務已修改而未提交的數據存在沖突(主鍵/唯一鍵沖突等),則後執行修改的事務會被掛起直到先執行修改的事務提交,但讀取不到造成沖突的數據,即幻讀
例如:表T有唯一鍵UK,事務A先向T插入UK=x但不提交,事務B再向T插入UK=x,此時事務B會被掛起;若事務A提交,此時事務B會因為唯一鍵沖突而報錯;若事務A刪除UK=x後提交,此時事務B的插入操作會成功;然而直到事務B提交之前,它都SELECT不到由事務A插入的UK=x。這是MySQL的默認隔離等級
4. serializable,序列化。事務必須串行執行,完全隔離
綜上:
首先,隔離等級是針對事務的SELECT操作而言的
其次,隔離等級是按照不隔離(髒讀)=>不可重復讀=>可重復讀但存在幻讀=>完全串行化(禁用並發,解決幻讀),逐步加強隔離的程度的
另:
網上對幻讀的理解存在很多錯誤的地方。如:
有些文章引用《高性能MySQL》中所講,MySQL的InnoDB引擎通過MVCC(多版本並發控制)在repeatable read級就已解決了幻讀的問題。實際是錯誤的,MVCC采用類似樂觀鎖的機制從原理上就無法解決幻讀,同時從上面的例子中也可以看出,幻讀問題在repeatable read級並未解決
有些文章采用了類似這樣的描述:當事務(A)讀取了一定范圍的數據後,另一個事務(B)在這個范圍中插入一些數據,當原事務(A)在這個范圍內更新數據的時候,就會“驚奇”地發現這些數據,如同“幻影”一般。這種描述很模糊,什麼叫“驚奇”,什麼叫“幻影”?結合前面所舉的例子可以看出,事務A之所以會“驚奇”地感知到這些數據,是因為它SELECT不到這些由事務B更新的數據,但這些數據會影響到A的操作,如同“幻影”一樣,看不到它,但它卻已經存在
最後,總結一下便於記憶,對於事務而言:
“讀未提交”是指不管其它事務是否提交都能讀到它們的數據
“讀已提交”是指只有當其它事務提交之後才能讀到它們的數據
“可重復讀”是指只有當自己提交了之後才能讀到其它事務提交的數據
“序列化”是指事務逐個執行,當前事務提交之前,其它都被掛起