【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的資料,id有3,4,5,那麼4,5和後面的數字都會被鎖定,像6,7...,為什麼要這樣?因為如果我們不鎖定沒有的資料,當加入了新的資料id=6,就會出現幻讀,間隙鎖避免了幻讀。
對主鍵或唯一索引,如果select查詢時where條件全部精确命中(=或者in),這種場景本身就不會出現幻讀,是以隻會加行記錄鎖。
快照讀
簡單的select操作(不包括 select ... lock in share mode, select ... for update)。
Read Committed隔離級别:每次select都生成一個快照讀。
Read Repeatable隔離級别:開啟事務後第一個select語句才是快照讀的地方,而不是一開啟事務就快照讀。
快照讀的實作方式:undolog和MVCC
undolog:
每行除了資料外 還有
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 , 復原和快照讀 都需要。
多版本并發控制MVCC:
如圖,開始隻有最下面一行記錄,
當事務1更改該行記錄時,會進行如下操作:
事務1 先用排它鎖鎖住該行記錄(目前讀,讀到最新資料然後獨占),複制到undolog,即圖中第二行記錄;再更新字段, 把自己的事務id填入DB_TRX_ID, 讓復原指針DB_ROLL_PTR 指向undolog中修改前的原資料(開始隻有最下面一行記錄)
事務2操作也是一樣, 産生了第三行記錄。
原文位址
https://www.cnblogs.com/wwcom123/p/10727194.html