幻讀指的是乙個事務在前後兩次查詢同乙個範圍的時候,後一次查詢看到了前一次查詢沒有看到的行。
在可重複讀隔離級別下,普通的查詢是快照讀(使用事務版本確定了資料的可見性),是不會看到別的事務插入的資料的。因此,幻讀在「當前讀」下才會出現
select *** from *** where c=5 for update 這種讀 使用的是當前讀
幻讀帶來的問題:
1.加鎖的語義破壞,比如說事務a中 select *** from *** where c=5 for update , 此時已經對c=5的記錄加了鎖,鎖的是它的id ,假設其id=1
然後另乙個事務b中 insert 了一條id=2的 c=5的記錄, 事務c 執行 update set c=1 where id=2, 仍然可以成功。 但是 加鎖的 語義是要鎖住所有c=5的記錄,事務a結束前不許其他事務操作,這樣這個語義就不符合了,因為c=5的記錄,在事務a沒結束之前,仍然在被其他事務更改。
2.主庫和從庫的一致性問題,比如說事務a中有將c=5 (id為1)的記錄都更新成100的操作, 事務b是插入c=5 (id為2)的記錄。 順序為事務a先開始,事務b先提交。
主庫的執行結果就是id=1的記錄更新成了100,id=2的記錄仍然為5。
但是在從庫 通過binlog同步過來的語句是 先收到事務b提交的語句,然後是事務a提交的語句,結果就是c=5的記錄都被更新c=100。
解決方案可以將binlog從statement改為row。
需要注意的是,即使將所有掃瞄到的行都加上鎖,也無法解決幻讀的問題,因為行鎖無法阻止新的記錄插入。
23.1 間隙鎖。
產生幻讀的原因是,行鎖只能鎖住行,但是新插入記錄這個動作,要更新的 是記錄之間的「間隙」。因此,為了解決幻讀問題,innodb 只好引入新的鎖,也就是間隙 鎖 (gap lock)。
間隙鎖,鎖的就是兩個值之間的空隙。
select * from t where d=5 for update
會給掃瞄到的記錄加上行鎖,同時在行記錄之間也加上間隙鎖。
跟間隙鎖存在衝突關係的,是「往這個間隙中插入乙個記錄」這個操 作。間隙鎖之間都不存在衝突關係。
間隙鎖和行鎖合稱 next-key lock,每個 next-key lock 是前開後閉區間
間隙鎖和 next-key lock 的引入,解決了幻讀的問題。
但是間隙鎖的引入,可能會導致同樣的語句鎖住更大的範圍,這其實是影響併發度的。
間隙鎖是在可重複讀隔離級別下才會生效的。所以,你如果把隔離級別設定為讀提交 的話,就沒有間隙鎖了。
加鎖的原則
原則 1:加鎖的基本單位是 next-key lock
原則 2:查詢過程中訪問到的物件才會加鎖。
優化 1:索引上的等值查詢,給唯一索引加鎖的時候,next-key lock 退化為行鎖
優化 2:索引上的等值查詢,向右遍歷時且最後乙個值不滿足等值條件的時候,next-
key lock 退化為間隙鎖。
注意的是
鎖是加在索引上的
根據原則2 只有訪問到的物件才會加鎖,如果某個查詢使用覆蓋索引,並不需要訪問主鍵
索引,主鍵索引上並不會加任何鎖,其他事務依然可以使用這個主鍵可以更新。
如果使用了for update ,那麼mysql會認為你有打算要更新,即使有覆蓋索引,也會把主鍵索引也加上鎖。
同理 如果你要用 lock in share mode 來給行加讀鎖避免資料被更新的話,就必須得繞過覆蓋索引的優化。
在刪除資料的時候盡量加 limit。這樣不僅可以控制 刪除資料的條數,讓操作更安全,還可以減小加鎖的範圍。
比如說一張表裡面有100條資料,你刪100條,加了limit 100之後,那麼只會鎖這100條資料,如果此時插入的話
id=101及以後的資料是可以被插入的。 但是如果不加,在刪除期間,無法插入。
可重複讀隔離級別遵守兩階段鎖協議,所有加鎖的資源,都是在事務提交或 者回滾的時候才釋放的。
讀提交隔離級別下還有乙個優化,即:語句執行過程中加上的行鎖,在語句執行完
成後,就要把「不滿足條件的行」上的行鎖直接釋放了,不需要等到事務提交。
也就是說,讀提交隔離級別下,鎖的範圍更小,鎖的時間更短,這也是不少業務都預設使用
讀提交隔離級別的原因。
mysql可重複讀和幻讀例項
mysql的預設事務級別是 可重複讀 其中可重複讀是通過mvcc來實現的又叫快照讀,在事務中的讀操作通過對當前的資料庫中記錄乙個版本,以後的讀操作只會讀取記錄的版本,因此相當於對資料庫的資料建立了乙個快照資料,因此叫做快照讀,其不用對資料庫中的資料進行加鎖又叫做樂觀鎖。同時rr事務級別的mysql通...
MySQL的不可重複讀和幻讀
不可重複讀 不可重複讀是指在同乙個事務中,兩次 或以上 查詢發現符合條件的資料記錄的字段值發生了變化,導致不可重複讀出現的原因主要是update操作 不可重複讀的例子 alice和bob開啟了資料庫的兩個事務 bob讀取post comment表中所有post id為1的資料 alice修改了pos...
mysql髒讀 不可重複讀和幻讀的區別
髒讀 乙個事務讀取到了另乙個事務還未提交得資料。例 事務a開啟,事務b開啟,賬戶有1000元,事務b轉賬轉入500元,事務a查詢賬戶,發現有1500元 髒讀產生 此時事務b發生了未知錯誤,事務回滾,賬戶變為原來的1000元,賬戶只有1000元,事務a卻查詢到1500元。不可重複讀 在乙個事務中,兩次...