-
當前讀:
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 , 回滾和快照讀 都需要。