沒有索引時,FOR UPDATE
會鎖住整個表
現在,你正在一本一本地翻看所有書,尋找“維修中”的書,并且你對管理員說:“在我清點和修改完之前,別人不能動這些書,也不能往這個范圍里加新書!”
-
問題1:如何鎖住你找到的“維修中”的書?
你每找到一本“維修中”的書,就給它貼上一個“正在處理,請勿觸碰”的標簽(行級排他鎖)。 -
問題2:如何防止別人“往這個范圍里加新書”?
這是最關鍵的。因為你沒有“狀態”的目錄卡片(沒有索引),你不知道“維修中”的書在圖書館的哪個具體位置。它們可能散落在圖書館的任何角落。- 你無法像有索引那樣,只鎖住“計算機類”書架的某個空位(間隙鎖)。
- 你正在全圖書館地毯式搜索。
- 如果允許其他管理員在你搜索的時候,隨便往任何一個空書架上放一本新的“維修中”的書,那么你就會遇到“幻讀”——你清點完后,發現多出了幾本你沒見過的“維修中”的書。
唯一的辦法就是:
為了確保在你搜索和處理期間,沒有任何新的“維修中”的書被偷偷放進來,圖書館管理員只能宣布:
“暫停營業!所有人都不能動任何書,也不能放新書進來,直到這位管理員清點完畢!”
這就是表級排他鎖。它鎖住了整個圖書館,確保了在你操作期間,沒有任何新的“維修中”的書能夠被插入,從而徹底避免了幻讀。
總結一下:
當 WHERE
條件中的字段沒有索引時,數據庫無法精確地定位和鎖定數據范圍。為了滿足 FOR UPDATE
語句防止幻讀的要求,它不得不采取最保守、最安全的策略——鎖定整個表。這就像為了防止一只老鼠跑進屋子,你把整個房子的大門都鎖死了。雖然有效,但代價是犧牲了其他人的自由(并發性)。
所以,為了提高數據庫的效率和并發性,對于那些經常用于 WHERE
條件,特別是用于 FOR UPDATE
的字段,強烈建議創建索引。