衆所周知,數據庫事務的隔離級別有四種:
read uncmmitted 讀未提交,事務中的修改,即使沒有提交,對其他事務也是可見的。
read commited 讀提交(也稱不可重複讀),一個事務開始直到提交之前,所做的任何修改對其他事務都是不可見的。
repeatable read 可重複讀,同一事務中,多次讀取同樣記錄的結果是一致的。
serializable 可串行化,強制事務串行執行,避免幻讀問題。
事務隔離級別和對應存在的問題如下圖:
使用MySQL語句來理解事務的隔離級別。
有一個員工表employee,定義如下圖,含三個字段id, name, salary。
一、讀未提交
0 alice工資每月5000,
1 老闆開始一個事務:將alice薪設置爲10000。
2 尚未提交事務時,alice查詢到自己的薪資是10000。
3 一會兒,老闆回滾了事務。此時Alice的薪資還是5000。可是Alice讀到了髒數據10000。
上面的事務執行update後,執行下面的語句,再執行上面事務中的回滾。
二、讀提交
讀提交,又稱不可重複讀,在該隔離級別下的同一個事務中,多次讀相同記錄,可能出現數據不一致。
開始事務,查詢alice的薪資,(另有人修改了alice的薪資),再次查詢alice的薪資,會發現兩次查詢得到的結果不一樣。詳情如下圖:
可以看到上圖事務中兩次讀取到的數據不一樣。
三、可重複讀
可重複讀解決了上面不可重複讀的問題。
其他事務的修改,對己事務不可見。在上圖事務兩次查詢中間,執行了下圖中的更新。可發現,上圖事務中兩次查詢的結果一致,可重複讀。
四、可串行化
圖中先開始執行的事務雖然沒有更新數據,但還沒結束呢。這時另一個事務要更新數據。因爲事務隔離級別是可串行化,強制事務串行執行,所以另一個事務就被阻塞了。長時間阻塞會超時退出:ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction。
另:還遺留一個問題,可重複讀隔離級別下如何復現幻讀現象?
現在再來看高性能MySQL書中的講解,是不是容易理解下圖了:)
參考鏈接:
如何編寫事務https://dev.mysql.com/doc/refman/5.7/en/commit.html
如何設置數據庫的隔離級別:https://dev.mysql.com/doc/refman/5.7/en/set-transaction.html