關於幻讀


不可重復讀
在同一事務中,兩次讀取同一數據,得到內容不同,側重點在於數據修改
幻讀
同一事務中,用同樣的操作讀取兩次,得到的記錄數不相同,幻讀的側重點在於兩次讀取的紀錄數量不一致
不可重復讀和幻讀在概念上有些交叉,對於不可重復讀來說,在同一個事務中,如果讀取到的記錄數量發生變化,也可以看作是一種不可重復讀,同樣,對於幻讀來說,同一個事務中的讀取結果數量一致,但是內容發生了變化,也可以看成是一種不可重復讀。
對於mysql,這里討論一下read committed和repeatable read兩個事務隔離級別的不可重復讀和幻讀:
read committed:
在read committed隔離級別下,存在不可重復讀和幻讀現象。
起兩個事務1和2,1采用快照讀讀取數據,2修改其中一條滿足1查詢條件的數據並提交,這時1再快照讀一次,就會發現2添加的記錄,這就是不可重復讀。但如果1采用當前讀方式讀取數據,由於讀取數據的時候會給滿足條件的數據加鎖,因此,事務2無法修改數據內容,如果單純從數據內容發生變化這個方面來考慮的話,是不會出現不可重復讀的問題的。同時,如果考慮到記錄數量增減,由於read committed隔離級別並沒有gap鎖,所以雖然不能修改采用當前讀方式鎖定的數據,但是可以在查詢條件滿足的范圍內增加新的數據,這也可以看作是一種不可重復讀,但顯然這種情況划分到幻讀更好。
repeatable read:
在repeatable read隔離級別下,mysql不僅解決了不可重復讀,還通過gap鎖的引入,解決了幻讀的問題。
具體分析與上邊類似,只是在repeatable隔離級別下,如果事務2對某些數據作了更新,事務1通過快照讀已經不會讀取到數據變化,所以repeatable read隔離級別解決了不可重復讀的問題。同時由於引入了gap鎖,事務2也無法在事務1采用當前讀的前提下在事務1的查詢條件滿足范圍內插入新的數據,所以記錄數量不會發生變化,也就不存在幻讀問題。
當隔離級別是可重復讀,且禁用innodb_locks_unsafe_for_binlog的情況下,才可以利用gap鎖避免幻讀,gap鎖是為了保證語句級別binlog的串行化。
總結:

  1. 如果僅僅考慮數據內容發生變化來衡量不可重復讀,那么只有在read committed隔離級別的快照讀中才會出現不可重復讀,如果考慮數據數量變化,那么在read committed隔離級別的快照讀和當前讀中都存在不可重復讀現象;
  2. read committed隔離級別下,快照讀和當前讀都會產生幻讀現象;
  3. repeatable read隔離級別下,只有快照讀會產生幻讀現象,當前讀已經通過gap鎖的引入消除了幻讀現象。
    (何登成大神在博客中將幻讀的定義限制在當前讀的前提下,個人認為還是幻讀和可重復讀的具體定義不清晰)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM