推薦(免費):SQL教學
#間隙鎖再加上行鎖,很容易判斷是否會出現鎖等待的問題上犯錯。
因為間隙鎖定在可重複讀取隔離等級下才有效,本文預設可重複讀取。
加鎖規則
- 原則1
加鎖的基本單位是next-key lock,前開後閉區間。 - 原則2
尋找過程中存取到的物件才會加鎖。 - 優化1
索引上的等值查詢,給唯一索引加鎖的時候,next-key lock退化為行鎖。 - 優化2
索引上的等值查詢,向右遍歷時且最後一個值不滿足等值條件的時候,next-key lock退化為間隙鎖定。 - 一個bug
唯一索引上的範圍查詢會存取到不滿足條件的第一個值為止。
資料準備
表名:t
新增資料:(0,0,0),(5,5,5), (10,10,10),(15,15,15),(20,20,20),(25,25,25)
接下來的例子基本上都是配合圖片說明的,所以我建議你可以對照著文稿看,有些例子可能會“毀三觀”,也建議你讀完文章後親手實踐一下。
案例
等值查詢間隙鎖定
等值查詢的間隙鎖定
表t中無id=7,所以根據原則1,加鎖單位next-key lock,所以session A加鎖範圍(5,10]
-
同時根據最佳化2,等值查詢(id=7),而id=10不滿足,next-key lock退化成間隙鎖,因此最終加鎖範圍(5,10)
所以,session B要往這個間隙裡面插入id=8的記錄會被鎖住,但是session C修改id=10這行是可以的。
非唯一索引等值鎖定
只加在非唯一索引上的鎖定
- ##session A要給索引c的c=5這行加讀鎖定
根據原則1,加鎖單位next-key lock,因此給(0,5]加next-key lock
c是
普通索引,因此只訪問c=5這條記錄不能馬上停下來,需要向右遍歷,查到c=10才放棄。根據原則2,訪問到的都要加鎖,因此要給(5,10]加next-key lock 同時符合優化2:等值判斷,向右遍歷,最後一個值不滿足c=5這個等值條件,因此退化成間隙鎖(5,10)
根據原則2 ,只有存取到的物件才會加鎖,這個查詢使用覆蓋索引,並不需要存取主鍵索引,所以主鍵索引上沒有加任何鎖,所以session B的update語句可以執行完成。
但session C要插入(7,7,7),就會被session A的間隙鎖(5,10)鎖住。
3 主鍵索引範圍鎖定
範圍查詢。 對於我們這個表t,下面這兩個查詢語句,加鎖範圍相同嗎? mysql> select * from t where id=10 for update; mysql> select * from t where id>=10 and id 你可能會想,id定義為int型,這兩個語句就是等價的吧?其實,它們並不完全等價。
現在我們就用前面提到的加鎖規則,來分析一下session A 會加什麼鎖呢?
再看看範圍查詢加鎖,你可以對照著案例三
非唯一索引範圍鎖定
session_1 | session_2 | session_3 |
---|---|---|
#begin; select * from t where c>=10 and c |
||
#insert into t values(8,8 ,8);(blocked) | ||
update t 設定 d =d 1 where c=15;(blocked) |
- #session1第一次用
c=10
定位記錄時,索引c加了(5,10] next-key lock
- c是非唯一索引,無最佳化規則,即不會退化為行鎖定
- 因此最終sesion1加鎖為c的
(5,10]
和(10,15]
next-key lock。
唯一索引範圍鎖定bug
前四案例用到兩個原則和兩個最佳化,再看加鎖規則bug案例。session_2 | session_3 | |
---|---|---|
where id>10 and id |
||
|
||
##update t | set d=d 1where id=20;(阻塞) |
-
##insert into t values(16,16,16);(阻塞)
session1是範圍查詢
(10,15] next-key lock
,因為id是唯一鍵,所以迴圈判斷到
這行就該停止遍歷。
但實作上,InnoDB會繼續掃描到第一個不滿足條件的行,即id=20
,且由於這是範圍掃描,因此id上的(15,20] next-key lock
也會被鎖。所以session2要更新id=20這行會被阻塞。
按理說鎖住id=20這行沒必要,因為唯一索引掃描到id=15即可確定不用繼續遍歷。但實現上還是這麼做了,可能是個bug。
為更好地說明「間隙」概念。
插入記錄7看如下案例。 | 6 | delete加鎖邏輯類似 |
---|---|---|
session_1 |
session_2 | session_3|
begin; delete * 從 t | where c=10||
- insert into t values(13,13,13);(阻塞)
#session1遍歷時先存取第一個c=10: |
依原則1,這裡加是(c=5,id=5)到(c=10,id=10) next-key lock | 然後,session1 向右找,直到碰到(c=15,id=15)這行,循環結束。根據最佳化2,等值查詢,向右查找到不滿足條件的行,所以退化成(c=10,id=10) 到(c=15,id=15)的間隙鎖(開區間,(c=5,id=5)和(c=15,id=15)這兩行無鎖)。
7 limit 語句加上鎖定 |
session1 的delete語句加了 limit 2。你知道表t裡c=10的記錄其實只有兩條,因此加不加limit 2,刪除的效果都是一樣的,但是加鎖的效果卻不同。可以看到,session B的insert語句執行通過了,跟案例六的結果不同。
這是因為,案例七里的delete語句明確加了limit 2的限制,因此在遍歷到(c=10, id=30)這一行之後,滿足條件的語句已經有兩條,循環就結束了。
因此,索引c上的加鎖範圍就變成了從(c=5,id=5)到(c=10,id=30)這個前開後閉區間,如下圖所示:
帶有limit 2的加鎖效果
可以看到,(c=10,id=30)之後的這個間隙並沒有在加鎖範圍裡,因此insert語句插入c=12是可以執行成功的。
這個例子對我們實踐的指導意義就是,在刪除資料的時候盡量加上limit。這樣不僅可以控制刪除資料的條數,讓操作更安全,還可以減少加鎖的範圍。
一個死鎖的例子
前面的例子中,我們在分析的時候,是依照next-key lock的邏輯來分析的,因為這樣分析比較方便。最後我們再看一個案例,目的是說明:next-key lock其實是間隙鎖和行鎖加起來的結果。
你一定會疑惑,這個概念不是一開始就說了嗎?不要急,我們先來看下面這個例子:
案例八的操作序列
#session A 啟動事務後執行查詢語句加lock in share mode,在索引c上加了next-key lock(5,10] 和間隙鎖(10,15);
session B 的update語句也要在索引c上加next-key lock(5,10] ,進入鎖定等待;
然後session A要再插入(8,8,8)這一行,被session B的間隙鎖鎖住。由於出現了死鎖,InnoDB讓session B回滾。
你可能會問,session B的next-key lock不是還沒申請成功嗎?
#其實是這樣的,session B的「加next-key lock(5,10] 」操作,實際上分成了兩步,先是加(5,10)的間隙鎖,加鎖成功;然後加c=10的行鎖,這時候才被鎖住的。
#也就是說,我們在分析加鎖規則的時候可以用next-key lock來分析。但是要知道,具體執行的時候,是要分成間隙鎖和行鎖兩段來執行的。
總結
所有案例都是在可重複讀取下驗證,可重複讀取遵守兩階段鎖定協議,所有加鎖的資源,都是在事務提交或回滾的時候才釋放。
在最後的案例中,你可以清楚地知道next-key lock實際上是由間隙鎖加行鎖實現的。如果切換到讀取提交隔離級別(read-committed)的話,就好理解了,過程中去掉間隙鎖的部分,也就是只剩下行鎖的部分。
在讀取提交隔離等級下還有一個最佳化,即:語句執行過程中加上的行鎖,在語句執行完成後,就要把「不符合條件的行」上的行鎖直接釋放了,不需要等到交易提交。
讀取提交隔離等級下,鎖的範圍更小,鎖的時間更短,所以不少業務也預設使用讀取提交。
在業務需要使用可重複讀取時,解決幻讀問題同時,最大限度提升系統並行處理事務的能力。
間隙鎖再加上行鎖,很容易在判斷是否會出現鎖定等待的問題上犯錯。
因為間隙鎖定在可重複讀取隔離等級下才有效,本文預設可重複讀取。
更多相關知識敬請造訪SQL免費欄位~~
#以上是驚!一行SQL語句竟然這麼多鎖..的詳細內容。更多資訊請關注PHP中文網其他相關文章!

SQL是一種用於管理關係數據庫的標準語言,而MySQL是一個具體的數據庫管理系統。 SQL提供統一語法,適用於多種數據庫;MySQL輕量、開源,性能穩定但在大數據處理上有瓶頸。

SQL學習曲線陡峭,但通過實踐和理解核心概念可掌握。 1.基礎操作包括SELECT、INSERT、UPDATE、DELETE。 2.查詢執行分為解析、優化、執行三步。 3.基本用法如查詢僱員信息,高級用法如使用JOIN連接表。 4.常見錯誤包括未使用別名和SQL注入,需使用參數化查詢防範。 5.性能優化通過選擇必要列和保持代碼可讀性實現。

SQL命令在MySQL中分為DQL、DDL、DML、DCL和TCL五類,用於定義、操作和控制數據庫數據。 MySQL通過詞法分析、語法分析、優化和執行等階段處理SQL命令,並利用索引和查詢優化器提升性能。使用示例包括SELECT用於數據查詢,JOIN用於多表操作。常見錯誤有語法、邏輯和性能問題,優化策略包括使用索引、優化查詢和選擇合適的存儲引擎。

SQL的高級查詢技巧包括子查詢、窗口函數、CTE和復雜JOIN,能夠處理複雜數據分析需求。 1)子查詢用於找出每個部門工資最高的員工。 2)窗口函數和CTE用於分析員工的薪資增長趨勢。 3)性能優化策略包括索引優化、查詢重寫和使用分區表。

MySQL是開源的關係型數據庫管理系統,提供了標準SQL功能和擴展。 1)MySQL支持標準SQL操作如CREATE、INSERT、UPDATE、DELETE,並擴展了LIMIT子句。 2)它使用InnoDB和MyISAM等存儲引擎,適用於不同場景。 3)用戶可以通過創建表、插入數據和使用存儲過程等高級功能高效使用MySQL。

sqlmakesdatamanagectAccessibletoAllbyProvidingAsimpleyetpoperfultoolSetSetForQuerquereingAndManagingDatabases.1)ItworkswithrelationalDatabases,允許inserstospecefifywhattheywanttododowithththedata.2)

SQL索引可以通过巧妙的设计显著提升查询性能。1.选择合适的索引类型,如B-tree、哈希或全文索引。2.使用复合索引优化多字段查询。3.避免过度索引以减少数据维护开销。4.定期维护索引,包括重建和移除不必要的索引。

在 SQL 中刪除約束,請執行以下步驟:識別要刪除的約束名稱;使用 ALTER TABLE 語句:ALTER TABLE 表名 DROP CONSTRAINT 約束名;確認刪除。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

SublimeText3 英文版
推薦:為Win版本,支援程式碼提示!

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

MinGW - Minimalist GNU for Windows
這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

SublimeText3漢化版
中文版,非常好用

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)