MYSQL的RR隔離級別是如何解決幻讀的


在MYSQL的RR隔離級別下, MYSQL也解決了幻讀的問題。 主要是依靠兩個特性解決的, 一個是MVCC(一致性快照) 一個是間隙鎖。

MVCC如何解決幻讀

begin select count(*) from table where id >10 ...... 一系列的其他操作 ...... select count(*) from table where id >10 commit 

 

上面的sql 語句如果在執行的過程中(中間的一系列操作中), 其他的事務新增了 id>10 的記錄, 這個sql語句的前后兩次查詢記錄的條數的結果還是一樣的。

為何會這樣是因為MYSQL的MVCC機制, 在事務開始的時候, 其實已經創建了一個快照, 后面的所有查詢都是查詢這個快照的, 所以查詢結果一樣,

至於MVCC的機制是如何作用的, MYSQL主要是記住各個事務的id, 並根據每行數據的事務id來進行比較來確定版本快照的, 具體機制大家可以搜下。

如果我們把語句改成這樣呢?

begin select count(*) from table where id >10 for update ...... 一系列的其他操作 ...... select count(*) from table where id >10 for update commit 

 

由於for update 的特性導致這個查詢語句是使用的當前讀, 並沒有使用快照。 那么快照就不能保證解決幻讀問題了。 這個時候就要用上間隙鎖的概念了。

間隙鎖保證幻讀正確

begin select count(*) from table where id >10 for update ## 10前面的一條記錄的id就是9 ...... 一系列的其他操作 ...... select count(*) from table where id >10 for update commit 

 

這個sql的事務在執行到第一個查詢語句的時候, 會加上間隙鎖的, 鎖住的范圍是(9,+無窮] . 那么其他的事務無法再這個id范圍進行任何的修改和插入操作了, 他們如果要操作就會堵住。

這樣mysql又通過間隙鎖的功能解決了幻讀問題,但是可以看到這個代價很大的, 僅次於全表寫鎖了。

間隙鎖的死鎖問題

正常的讀寫鎖之間的互斥關系我們很清楚,但是間隙鎖呢, 間隙鎖與間隙鎖之間是不互斥的。 就是一個事務A鎖住了(0,100]的間隙鎖,那么B事務也可以重復獲取(0,100]的間隙鎖。

上面兩個事務都獲取了間隙鎖, 這個時候如果A事務要在這個間隙之間插入一條記錄,會阻塞,因為B事務間隙鎖了, 同樣B事務也不能操作這個間隙了。 這樣就導致了兩個線程形成死鎖了。

這就是代價,是InnoDB解決幻讀的代價。


免責聲明!

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



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