mysql筆記系列 十八 幻讀和間隙鎖

2021-10-04 02:57:13 字數 2080 閱讀 7899

幻讀指的是乙個事務在前後兩次查詢同乙個範圍的時候,後一次查詢看到了前一次查詢沒有看到的行。

在可重複讀隔離級別下,普通的查詢是快照讀(使用事務版本確定了資料的可見性),是不會看到別的事務插入的資料的。因此,幻讀在「當前讀」下才會出現

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元。不可重複讀 在乙個事務中,兩次...