1. 程式人生 > 其它 >行鎖,間隙鎖,快照讀,當前讀的理解。 【MySQL】當前讀、快照讀、MVCC

行鎖,間隙鎖,快照讀,當前讀的理解。 【MySQL】當前讀、快照讀、MVCC

https://www.bilibili.com/video/BV1LC4y1h7VV?spm_id_from=333.337.search-card.all.click

 

 比如我們進行精準查詢後在事務提交前(左圖),此時對應行鎖,阻止其它事務修改該記錄行(右圖)。

當我們對沒有加索引的資料列進行查詢的時候因為走的是整張表,所以此時升級為表鎖,對整張表的任何修改都會被堵塞,這時效率會很低。

 

 or操作導致索引失效,右邊的事務被堵塞。

 

 對於範圍資料進行查詢會加入範圍鎖,事務提交前會被堵塞,右邊的則是被堵塞。

【MySQL】當前讀、快照讀、MVCC - wwcom123 - 部落格園 (cnblogs.com)

【MySQL】當前讀、快照讀、MVCC

 
  • 當前讀:

  select...lock in share mode (共享讀鎖)
  select...for update
  update , delete , insert

  當前讀, 讀取的是最新版本, 並且對讀取的記錄加鎖, 阻塞其他事務同時改動相同記錄,避免出現安全問題

  例如,假設要update一條記錄,但是另一個事務已經delete這條資料並且commit了,如果不加鎖就會產生衝突。所以update的時候肯定要是當前讀,得到最新的資訊並且鎖定相應的記錄。

  

  • 當前讀的實現方式:next-key鎖(行記錄鎖+Gap間隙鎖)

   間隙鎖:只有在Read Repeatable、Serializable隔離級別才有,就是鎖定範圍空間的資料,假設id有3,4,5,鎖定id>3的資料,是指的4,5及後面的數字都會被鎖定,因為此時如果不鎖定沒有的資料,例如當加入了新的資料id=6,就會出現幻讀,間隙鎖避免了幻讀。

  1.對主鍵或唯一索引,如果當前讀時,where條件全部精確命中(=或者in),這種場景本身就不會出現幻讀,所以只會加行記錄鎖。

  2.沒有索引的列(或者索引失效),當前讀操作時,會加全表gap鎖,生產環境要注意。

  3.非唯一索引列,如果where條件部分命中(>、<、like等)或者全未命中,則會加附近Gap間隙鎖

。例如,某表資料如下,非唯一索引2,6,9,9,11,15。如下語句要操作非唯一索引列9的資料,gap鎖將會鎖定的列是(6,11],該區間內無法插入資料。

 

   

 

  •  快照讀

  單純的select操作,不包括上述 select ... lock in share mode, select ... for update。    

  Read Committed隔離級別:每次select都生成一個快照讀。

  Read Repeatable隔離級別:開啟事務後第一個select語句才是快照讀的地方,而不是一開啟事務就快照讀。

 

  • 快照讀的實現方式:undolog和多版本併發控制MVCC

  下圖右側綠色的是資料:一行資料記錄,主鍵ID是10,name='Jack',age=10,  被update更新set為name= 'Tom',age=23。

  事務會先使用“排他鎖”鎖定改行,將該行當前的值複製到undo log中,然後再真正地修改當前行的值,最後填寫事務的DB_TRX_ID,使用回滾指標DB_ROLL_PTR指向undo log中修改前的行DB_ROW_ID

'

  DB_TRX_ID: 6位元組DB_TRX_ID欄位,表示最後更新的事務id(update,delete,insert)。此外,刪除在內部被視為更新,其中行中的特殊位被設定為將其標記為已軟刪除。

  DB_ROLL_PTR: 7位元組回滾指標,指向前一個版本的undolog記錄,組成undo連結串列。如果更新了行,則撤消日誌記錄包含在更新行之前重建行內容所需的資訊。
  DB_ROW_ID: 6位元組的DB_ROW_ID欄位,包含一個隨著新行插入而單調遞增的行ID, 當由innodb自動產生聚集索引時,聚集索引會包括這個行ID的值,否則這個行ID不會出現在任何索引中。如果表中沒有主鍵或合適的唯一索引, 也就是無法生成聚簇索引的時候, InnoDB會幫我們自動生成聚集索引, 聚簇索引會使用DB_ROW_ID的值來作為主鍵; 如果表中有主鍵或者合適的唯一索引, 那麼聚簇索引中也就不會包含 DB_ROW_ID了 。  

  其它:insert undo log只在事務回滾時需要, 事務提交就可以刪掉了。update undo log包括update 和 delete , 回滾和快照讀 都需要。

  • 當前讀:

  select...lock in share mode (共享讀鎖)
  select...for update
  update , delete , insert

  當前讀, 讀取的是最新版本, 並且對讀取的記錄加鎖, 阻塞其他事務同時改動相同記錄,避免出現安全問題

  例如,假設要update一條記錄,但是另一個事務已經delete這條資料並且commit了,如果不加鎖就會產生衝突。所以update的時候肯定要是當前讀,得到最新的資訊並且鎖定相應的記錄。

  

  • 當前讀的實現方式:next-key鎖(行記錄鎖+Gap間隙鎖)

   間隙鎖:只有在Read Repeatable、Serializable隔離級別才有,就是鎖定範圍空間的資料,假設id有3,4,5,鎖定id>3的資料,是指的4,5及後面的數字都會被鎖定,因為此時如果不鎖定沒有的資料,例如當加入了新的資料id=6,就會出現幻讀,間隙鎖避免了幻讀。

  1.對主鍵或唯一索引,如果當前讀時,where條件全部精確命中(=或者in),這種場景本身就不會出現幻讀,所以只會加行記錄鎖。

  2.沒有索引的列(或者索引失效),當前讀操作時,會加全表gap鎖,生產環境要注意。

  3.非唯一索引列,如果where條件部分命中(>、<、like等)或者全未命中,則會加附近Gap間隙鎖。例如,某表資料如下,非唯一索引2,6,9,9,11,15。如下語句要操作非唯一索引列9的資料,gap鎖將會鎖定的列是(6,11],該區間內無法插入資料。

 

   

 

  •  快照讀

  單純的select操作,不包括上述 select ... lock in share mode, select ... for update。    

  Read Committed隔離級別:每次select都生成一個快照讀。

  Read Repeatable隔離級別:開啟事務後第一個select語句才是快照讀的地方,而不是一開啟事務就快照讀。

 

  • 快照讀的實現方式:undolog和多版本併發控制MVCC

  下圖右側綠色的是資料:一行資料記錄,主鍵ID是10,name='Jack',age=10,  被update更新set為name= 'Tom',age=23。

  事務會先使用“排他鎖”鎖定改行,將該行當前的值複製到undo log中,然後再真正地修改當前行的值,最後填寫事務的DB_TRX_ID,使用回滾指標DB_ROLL_PTR指向undo log中修改前的行DB_ROW_ID

'

  DB_TRX_ID: 6位元組DB_TRX_ID欄位,表示最後更新的事務id(update,delete,insert)。此外,刪除在內部被視為更新,其中行中的特殊位被設定為將其標記為已軟刪除。

  DB_ROLL_PTR: 7位元組回滾指標,指向前一個版本的undolog記錄,組成undo連結串列。如果更新了行,則撤消日誌記錄包含在更新行之前重建行內容所需的資訊。
  DB_ROW_ID: 6位元組的DB_ROW_ID欄位,包含一個隨著新行插入而單調遞增的行ID, 當由innodb自動產生聚集索引時,聚集索引會包括這個行ID的值,否則這個行ID不會出現在任何索引中。如果表中沒有主鍵或合適的唯一索引, 也就是無法生成聚簇索引的時候, InnoDB會幫我們自動生成聚集索引, 聚簇索引會使用DB_ROW_ID的值來作為主鍵; 如果表中有主鍵或者合適的唯一索引, 那麼聚簇索引中也就不會包含 DB_ROW_ID了 。  

  其它:insert undo log只在事務回滾時需要, 事務提交就可以刪掉了。update undo log包括update 和 delete , 回滾和快照讀 都需要。