共計(jì) 1888 個(gè)字符,預(yù)計(jì)需要花費(fèi) 5 分鐘才能閱讀完成。
這篇文章主要為大家展示了“InnoDB 中 select 查詢(xún)是行鎖還是表鎖”,內(nèi)容簡(jiǎn)而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓丸趣 TV 小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“InnoDB 中 select 查詢(xún)是行鎖還是表鎖”這篇文章吧。
之前說(shuō) InnoDB 的 select 查詢(xún)會(huì)鎖表,有的人不信。然而有的人學(xué)習(xí)能力很強(qiáng),立馬在官方網(wǎng)站上找到了,select 查詢(xún)會(huì)鎖表,就看你怎么使用,并不是說(shuō)所有的 select 查詢(xún)都會(huì)鎖表。具體看你的事務(wù)隔離級(jí)別,和編寫(xiě)的查詢(xún)語(yǔ)句的形式。
MySQL 最常見(jiàn)的坑就是 InnoDB 是行鎖,這是大家都知道的事,但是有時(shí)候它卻會(huì)鎖表,你說(shuō)奇怪不奇怪。
其實(shí)只要你懂它了之后,一點(diǎn)也不會(huì)覺(jué)得奇怪。只有你不懂,才會(huì)覺(jué)得它奇怪。InnoDB 的行鎖是實(shí)現(xiàn)在索引上的,而不是鎖在物理行記錄上。潛臺(tái)詞是,如果訪問(wèn)沒(méi)有命中索引,也無(wú)法使用行鎖,將要退化為表鎖。這一點(diǎn)和 Oracle 的行鎖實(shí)現(xiàn)機(jī)制略有不同。
例如下面的表:
1
xttblog(id, title, url, text) innodb;
id PK(主鍵),無(wú)其他索引,即其他列都沒(méi)有索引。
1
update xttblog set text= 業(yè)余草 where id=1;
命中索引,行鎖。
1
update xttblog set text= 業(yè)余草 where id != 1;
未命中索引,表鎖。
1
update xttblog set text= 業(yè)余草 where title= 業(yè)余草 ;
無(wú)索引,表鎖。
啟示:InnoDB 務(wù)必建好索引,否則鎖粒度較大,會(huì)影響并發(fā)。
再說(shuō)一下 select,如果查詢(xún)沒(méi)有命中索引,也將退化為表鎖。下面我們結(jié)合 InnoDB 的三種鎖(記錄鎖 (Record Locks)、間隙鎖 (Gap Locks)、臨鍵鎖 (Next-Key Locks))來(lái)說(shuō)明它。再講這三種鎖的前提條件是默認(rèn)的事務(wù)隔離級(jí)別為可重復(fù)讀 (Repeated Read, RR)。
記錄鎖 (Record Locks)
記錄鎖,它封鎖索引記錄,例如下面的查詢(xún)語(yǔ)句:
1
select * from xttblog where id=1 for update;
它會(huì)在 id=1 的索引記錄上加鎖,以阻止其他事務(wù)插入,更新,刪除 id=1 的這一行。
需要說(shuō)明的是,如果是下面的查詢(xún)語(yǔ)句:
1
select * from xttblog where id=1;
則是快照讀 (SnapShot Read),它并不加鎖。
間隙鎖 (Gap Locks)
間隙鎖,它封鎖索引記錄中的間隔,或者第一條索引記錄之前的范圍,又或者最后一條索引記錄之后的范圍。例如下面的 SQL 語(yǔ)句:
1
select * from xttblog where id between 8 and 15 for update;
會(huì)封鎖區(qū)間 id 為 8 到 15 的記錄。以阻止其他事務(wù),如:id=10 的記錄插入。
如果不阻止 id=10 的記錄插入,則會(huì)產(chǎn)生幻讀。如果能夠插入成功,同一個(gè)事務(wù)執(zhí)行相同的 SQL 語(yǔ)句,會(huì)發(fā)現(xiàn)結(jié)果集多出了一條記錄,即幻讀數(shù)據(jù)。
間隙鎖的主要目的,就是為了防止其他事務(wù)在間隔中插入數(shù)據(jù),以導(dǎo)致“不可重復(fù)讀”。
如果把事務(wù)的隔離級(jí)別降級(jí)為讀提交 (Read Committed, RC),間隙鎖則會(huì)自動(dòng)失效。
臨鍵鎖 (Next-Key Locks)
臨鍵鎖,是記錄鎖與間隙鎖的組合,它的封鎖范圍,既包含索引記錄,又包含索引區(qū)間。臨鍵鎖會(huì)封鎖索引記錄本身,以及索引記錄之前的區(qū)間。
如果一個(gè)會(huì)話(huà)占有了索引記錄 Record 的共享 / 排他鎖,其他會(huì)話(huà)不能立刻在 Record 之前的區(qū)間插入新的索引記錄。臨鍵鎖的主要目的,也是為了避免幻讀 (Phantom Read)。如果把事務(wù)的隔離級(jí)別降級(jí)為 RC,臨鍵鎖則也會(huì)失效。
最后說(shuō)一下,怎么測(cè)試當(dāng)前的查詢(xún)到底是行鎖還是表鎖呢?
以我們之前發(fā)生事故來(lái)說(shuō),首先是 select 查詢(xún)不能有索引。然后 dev 環(huán)境和 sit 環(huán)境連接同一個(gè)數(shù)據(jù)庫(kù),dev 對(duì)某個(gè)事務(wù)中的查詢(xún)?nèi)帱c(diǎn),讓它停在查詢(xún)操作上;sit 環(huán)境則對(duì)同一個(gè)表進(jìn)行插入、更新、刪除操作。查看日志,就會(huì)發(fā)現(xiàn)有 time out 日志。具體為事務(wù)無(wú)法提交,超時(shí)結(jié)束,因?yàn)檫@個(gè)表已經(jīng)被鎖住了,獲取不到鎖,就會(huì)發(fā)生超時(shí)。
總結(jié):InnoDB 的鎖,與索引類(lèi)型,事務(wù)的隔離級(jí)別相關(guān)。InnoDB 到底是行鎖還是表鎖取決于你的 SQL 語(yǔ)句。如果查詢(xún)沒(méi)有命中索引,也將退化為表鎖。InnoDB 的行鎖是實(shí)現(xiàn)在索引上的,而不是鎖在物理行記錄上。所以如果訪問(wèn)沒(méi)有命中索引,也無(wú)法使用行鎖,將要退化為表鎖。
以上是“InnoDB 中 select 查詢(xún)是行鎖還是表鎖”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注丸趣 TV 行業(yè)資訊頻道!