您好,登錄后才能下訂單哦!
這篇文章主要為大家展示了“InnoDB中select查詢是行鎖還是表鎖”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“InnoDB中select查詢是行鎖還是表鎖”這篇文章吧。
之前說InnoDB 的 select 查詢會鎖表,有的人不信。然而有的人學習能力很強,立馬在官方網站上找到了,select 查詢會鎖表,就看你怎么使用,并不是說所有的 select 查詢都會鎖表。具體看你的事務隔離級別,和編寫的查詢語句的形式。
MySQL 最常見的坑就是 InnoDB 是行鎖,這是大家都知道的事,但是有時候它卻會鎖表,你說奇怪不奇怪。
其實只要你懂它了之后,一點也不會覺得奇怪。只有你不懂,才會覺得它奇怪。InnoDB 的行鎖是實現在索引上的,而不是鎖在物理行記錄上。潛臺詞是,如果訪問沒有命中索引,也無法使用行鎖,將要退化為表鎖。這一點和 Oracle 的行鎖實現機制略有不同。
例如下面的表:
1 |
|
id PK(主鍵),無其他索引,即其他列都沒有索引。
1 |
|
命中索引,行鎖。
1 |
|
未命中索引,表鎖。
1 |
|
無索引,表鎖。
啟示:InnoDB 務必建好索引,否則鎖粒度較大,會影響并發。
再說一下 select,如果查詢沒有命中索引,也將退化為表鎖。下面我們結合 InnoDB 的三種鎖(記錄鎖(Record Locks)、間隙鎖(Gap Locks)、臨鍵鎖(Next-Key Locks))來說明它。再講這三種鎖的前提條件是默認的事務隔離級別為可重復讀(Repeated Read, RR)。
記錄鎖,它封鎖索引記錄,例如下面的查詢語句:
1 |
|
它會在 id=1 的索引記錄上加鎖,以阻止其他事務插入,更新,刪除 id=1 的這一行。
需要說明的是,如果是下面的查詢語句:
1 |
|
則是快照讀(SnapShot Read),它并不加鎖。
間隙鎖,它封鎖索引記錄中的間隔,或者第一條索引記錄之前的范圍,又或者最后一條索引記錄之后的范圍。例如下面的 SQL 語句:
1 |
|
會封鎖區間 id 為 8 到 15 的記錄。以阻止其他事務,如:id=10 的記錄插入。
如果不阻止 id=10 的記錄插入,則會產生幻讀。如果能夠插入成功,同一個事務執行相同的 SQL 語句,會發現結果集多出了一條記錄,即幻讀數據。
間隙鎖的主要目的,就是為了防止其他事務在間隔中插入數據,以導致“不可重復讀”。
如果把事務的隔離級別降級為讀提交(Read Committed, RC),間隙鎖則會自動失效。
臨鍵鎖,是記錄鎖與間隙鎖的組合,它的封鎖范圍,既包含索引記錄,又包含索引區間。臨鍵鎖會封鎖索引記錄本身,以及索引記錄之前的區間。
如果一個會話占有了索引記錄 Record 的共享/排他鎖,其他會話不能立刻在 Record 之前的區間插入新的索引記錄。臨鍵鎖的主要目的,也是為了避免幻讀(Phantom Read)。如果把事務的隔離級別降級為RC,臨鍵鎖則也會失效。
最后說一下,怎么測試當前的查詢到底是行鎖還是表鎖呢?
以我們之前發生事故來說,首先是 select 查詢不能有索引。然后 dev 環境和 sit 環境連接同一個數據庫,dev 對某個事務中的查詢取斷點,讓它停在查詢操作上;sit 環境則對同一個表進行插入、更新、刪除操作。查看日志,就會發現有 time out 日志。具體為事務無法提交,超時結束,因為這個表已經被鎖住了,獲取不到鎖,就會發生超時。
總結:InnoDB 的鎖,與索引類型,事務的隔離級別相關。InnoDB 到底是行鎖還是表鎖取決于你的 SQL 語句。如果查詢沒有命中索引,也將退化為表鎖。InnoDB 的行鎖是實現在索引上的,而不是鎖在物理行記錄上。所以如果訪問沒有命中索引,也無法使用行鎖,將要退化為表鎖。
以上是“InnoDB中select查詢是行鎖還是表鎖”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。