作者簡介
無為懒鉴,多年 MySQL DBA 工作經(jīng)驗(yàn)爬虱,現(xiàn)就職于某知名互聯(lián)網(wǎng)公司拱燃,對(duì) MySQL秉溉、 Redis、PostgrepSQL 等主流數(shù)據(jù)庫有一定了解碗誉,擁有豐富的一線運(yùn)維經(jīng)驗(yàn)召嘶。
涉及到 MySQL 的面試時(shí),是不是經(jīng)常會(huì)被問到當(dāng)前讀和快照讀的區(qū)別哮缺?
本節(jié)內(nèi)容就來聊聊這個(gè)話題弄跌,首先從快照讀開始:
1 普通讀
1.1 定義
普通讀(也稱快照讀,英文名:Consistent Read)尝苇,就是單純的 SELECT 語句铛只,不包括下面這兩類語句:
SELECT ... FOR UPDATE
SELECT ... LOCK IN SHARE MODE
普通讀的執(zhí)行方式是生成 ReadView埠胖,直接利用 MVCC 機(jī)制來進(jìn)行讀取,并不會(huì)對(duì)記錄進(jìn)行加鎖格仲。
小貼士
對(duì)于 SERIALIZABLE 隔離級(jí)別來說押袍,如果 autocommit 系統(tǒng)變量被設(shè)置為OFF,那普通讀的語句會(huì)轉(zhuǎn)變?yōu)殒i定讀凯肋,和在普通的 SELECT 語句后邊加 LOCK IN SHARE MODE 達(dá)成的效果一樣谊惭。
1.2 實(shí)現(xiàn)方式
普通讀是通過 undo log + MVCC 來實(shí)現(xiàn)的,具體我們?cè)僮屑?xì)聊聊:
下圖右側(cè)黃色部分是數(shù)據(jù):一行數(shù)據(jù)記錄侮东,主鍵 ID 是 10圈盔,object = 'Goland' ?,被 update 更新為 object = 'Python' 悄雅。
事務(wù)會(huì)先使用“排他鎖”鎖定該行驱敲,將該行當(dāng)前的值復(fù)制到 undo log 中,然后再真正地修改當(dāng)前行的值宽闲,最后填寫事務(wù)的 DB_TRX_ID 众眨,使用回滾指針 DB_ROLL_PTR 指向 undo log 中修改前的行。
這里解釋一下DB_TRX_ID 和DB_ROLL_PTR 所代表的含義:
DB_TRX_ID?: ?6 字節(jié) DB_TRX_ID 字段容诬,表示最后更新的事務(wù) id ( update , delete , insert ) 娩梨。此外,刪除在內(nèi)部被視為更新览徒,其中行中的特殊位被設(shè)置為將其標(biāo)記為已軟刪除狈定。
DB_ROLL_PTR?: ?7 字節(jié)回滾指針,指向前一個(gè)版本的 undo log 記錄习蓬,組成 undo 鏈表纽什。如果更新了行,則撤消日志記錄包含在更新行之前重建行內(nèi)容所需的信息躲叼。
小貼士
insert undo log 只在事務(wù)回滾時(shí)需要, 事務(wù)提交就可以刪掉了芦缰。update undo log 包括 update 和 delete , 回滾和快照讀都需要。
2 當(dāng)前讀
聊完快照讀枫慷,再聊聊當(dāng)前讀(也稱鎖定讀饺藤,Locking Read)。
2.1 定義
當(dāng)前讀流礁,讀取的是最新版本涕俗,并且需要先獲取對(duì)應(yīng)記錄的鎖,如以下這些 SQL 類型:
select?...?lock?in?share?mode?神帅、
select?...?for?update再姑、
update?、delete 找御、insert
當(dāng)然元镀,獲取什么類型的鎖取決于當(dāng)前事務(wù)的隔離級(jí)別绍填、語句的執(zhí)行計(jì)劃、查詢條件等因素栖疑。例如讨永,要 update 一條記錄,在事務(wù)執(zhí)行過程中遇革,如果不加鎖卿闹,那么另一個(gè)事務(wù)可以 delete 這條數(shù)據(jù)并且能成功 commit ,就會(huì)產(chǎn)生沖突了萝快。所以 update 的時(shí)候肯定要是當(dāng)前讀锻霎,得到最新的信息并且鎖定相應(yīng)的記錄。
2.2 實(shí)現(xiàn)方式
當(dāng)前讀是通過 next-key 鎖(行記錄鎖+間隙鎖)來是實(shí)現(xiàn)的揪漩。
這里補(bǔ)充下行鎖的 3 種算法:
行鎖(Record Lock):鎖直接加在索引記錄上面旋恼。
間隙鎖(Gap Lock):是 Innodb 為了解決幻讀問題時(shí)引入的鎖機(jī)制,所以只有在 Read Repeatable 奄容、Serializable 隔離級(jí)別才有冰更。
Next-Key Lock :Record Lock + Gap Lock,鎖定一個(gè)范圍并且鎖定記錄本身 昂勒。
下面通過一個(gè)例子來說明當(dāng)前讀的實(shí)現(xiàn)方式蜀细,例如下面這條 SQL:
delete?from?T?where?age =?7;
進(jìn)行下面的實(shí)驗(yàn):
測(cè)試可知 delete from T where age = 7; 語句在 age 上的加鎖區(qū)間為 (4,10) ,圖解如下:
歡迎加入 MySQL 交流社群
群內(nèi)不定期邀請(qǐng)一些身邊的大牛
交流分享,解答工作中遇到的的問題
分享工作經(jīng)驗(yàn)叁怪、(微yzlkf09)面試技巧等审葬!
也歡迎各位大牛投稿深滚,內(nèi)容可以是數(shù)據(jù)庫奕谭、開發(fā)、運(yùn)維痴荐、產(chǎn)品血柳、運(yùn)營等!
悅專欄 LIKECOLUMN
在這里生兆,學(xué)好編程
做更優(yōu)秀的 IT人难捌!