最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MySQL全局鎖、表鎖、行鎖、間隙鎖、臨鍵鎖超詳細講解

 更新時間:2026年01月13日 11:01:41   作者:小馬不敲代碼  
鎖是計算機用以協(xié)調多個進程間并發(fā)訪問同一共享資源的一種機制,MySQL中為了保證數據訪問的一致性與有效性等功能,實現(xiàn)了鎖機制,這篇文章主要介紹了MySQL全局鎖、表鎖、行鎖、間隙鎖、臨鍵鎖超詳細講解的相關資料,需要的朋友可以參考下

并發(fā)事務訪問相同記錄的情況大致可以劃分以下幾種:

  • 讀-讀情況:即并發(fā)事務相繼讀取相同的記錄。讀取操作本身不會對記錄有一毛錢影響,并不會引起什么問題,所以允許這種情況的發(fā)生。
  • 寫-寫情況:即并發(fā)事務相繼對相同的記錄做出改動。

作為多用戶共享的資源,當出現(xiàn)并發(fā)訪問的時候,數據庫需要合理地控制資源的訪問規(guī)則。

而鎖就是用來實現(xiàn)這些訪問規(guī)則的重要數據結構。

根據加鎖的范圍,MySQL 的鎖可以分為全局鎖、表鎖和行鎖。

“
對于MyISAM、MEMORY、MERGE這些存儲引擎來說,它們只支持表級鎖,而且這些引擎并不支持事務,所以使用這些存儲引擎的鎖一般都是針對當前會話來說的。

全局鎖

全局鎖就是對整個數據庫實例加鎖。MySQL 提供了一個加全局讀鎖的方法,命令是 Flush tables with read lock (FTWRL)。

當你需要讓整個庫處于只讀狀態(tài)的時候,可以使用這個命令,之后其他線程的以下語句會被阻塞。

  • 數據更新語句(數據的增刪改)
  • 數據定義語句(包括建表、修改表結構等)
  • 更新類事務的提交語句。

全局鎖的適應場景之一,做全庫的邏輯備份。把整個庫的表數據都查出來存儲為文本。

讓整庫都只讀,在備份期間都不能執(zhí)行更新,業(yè)務基本上就得停擺。這怎么辦?

  • 如果你在主庫上備份,那么在備份期間都不能執(zhí)行更新,業(yè)務基本上就得停擺;
  • 如果你在從庫上備份,那么備份期間從庫不能執(zhí)行主庫同步過來的 binlog,會導致主從延遲。

不加鎖產生的問題
比如手機卡,購買套餐信息。這里分為兩張表 u_acount (用于余額表),u_pricing (資費套餐表)。

  • u_account 表中數據 用戶 A 余額:300;u_pricing 表中數據 用戶 A 套餐:空
  • 發(fā)起備份,備份過程中先備份 u_account 表,備份完了這個表,這個時候 u_account 用戶余額是 300。
  • 這個時候套用戶購買了一個資費套餐 100,餐購買完成,寫入到 u_print 套餐表購買成功,備份期間的數據。
  • 備份完成。

可以看到備份的結果是,u_account 表中的數據沒有變, u_pricing 表中的數據 已近購買了資費套餐 100.

哪這時候用這個備份文件來恢復數據的話,用戶 A 賺了 100 ,用戶是不是很舒服啊。但是你的想想公司利益啊。

也就是說,不加鎖的話,備份系統(tǒng)備份的得到的庫不是一個邏輯時間點,這個數據是邏輯不一致的。

表級鎖

MySQL 里面表級別的鎖有兩種:一種是表鎖,一種是元數據鎖(meta data lock,MDL)。

表鎖的語法是 lock tables … read/write。與 FTWRL 類似,可以用 unlock tables 主動釋放鎖,也可以在客戶端斷開的時候自動釋放。

另一類表級的鎖是 MDL(metadata lock)。MDL 不需要顯式使用,在訪問一個表的時候會被自動加上。

當對一個表做增刪改查操作的時候,加 MDL 讀鎖;當要對表做結構變更操作的時候,加 MDL 寫鎖。

  • 讀鎖之間不互斥,因此你可以有多個線程同時對一張表增刪改查。
  • 讀寫鎖之間、寫鎖之間是互斥的,用來保證變更表結構操作的安全性。

不過請盡量避免在使用InnoDB存儲引擎的表上使用LOCK TABLES這樣的手動鎖表語句,它們并不會提供什么額外的保護,只是會降低并發(fā)能力而已。

InnoDB的厲害之處還是實現(xiàn)了更細粒度的行鎖,關于表級別的鎖大家了解一下就罷了。

在使用MySQL過程中,我們可以為表的某個列添加AUTO_INCREMENT屬性。之后在插入記錄時,可以不指定該列的值,系統(tǒng)會自動為它賦上遞增的值。

這是什么鎖?

比方說我們有一個表:

CREATE TABLE t (
    id INT NOT NULL AUTO_INCREMENT,
    c VARCHAR(100),
    PRIMARY KEY (id)
) Engine=InnoDB CHARSET=utf8;

系統(tǒng)實現(xiàn)這種自動給AUTO_INCREMENT修飾的列遞增賦值的原理主要是兩個:

1、采用表級別AUTO-INC鎖,然后為每條待插入記錄的AUTO_INCREMENT修飾的列分配遞增的值,在該語句執(zhí)行結束后,再把AUTO-INC鎖釋放掉。

  • 這樣一個事務在持有AUTO-INC鎖的過程中,其他事務的插入語句都要被阻塞,可以保證一個語句中分配的遞增值是連續(xù)的。
  • 如果我們的插入語句在執(zhí)行前不可以確定具體要插入多少條記錄(無法預計即將插入記錄的數量),比方說使用INSERT … SELECT、REPLACE … SELECT或者LOAD DATA這種插入語句,一般是使用AUTO-INC鎖為AUTO_INCREMENT修飾的列生成對應的值。

2、輕量級的鎖,這種方式可以避免鎖定表,可以提升插入性能:

  • 在為插入語句生成AUTO_INCREMENT修飾的列的值時獲取一下這個輕量級鎖,然后生成本次插入語句需要用到的AUTO_INCREMENT列的值之后,就把該輕量級鎖釋放掉,并不需要等到整個插入語句執(zhí)行完才釋放鎖。
  • 如果我們的插入語句在執(zhí)行前就可以確定具體要插入多少條記錄,比方說我們上邊舉的關于表t的例子中,在語句執(zhí)行前就可以確定要插入 2 條記錄,那么一般采用輕量級鎖的方式對AUTO_INCREMENT修飾的列進行賦值。

行鎖

行鎖,也稱為記錄鎖,顧名思義就是在記錄上加的鎖。這是最復雜的鎖,前面的只是開胃菜。

一個行鎖玩出了各種花樣,也就是把行鎖分成了各種類型。

MySQL 的行級鎖是 InnoDB 存儲引擎實現(xiàn)高并發(fā)的核心技術之一。它允許在保證數據一致性的同時,大幅提升數據庫的并發(fā)處理能力。

下面這張表格匯總了行級鎖的主要類型和核心特點,可以幫助你快速建立整體印象。

共享鎖與排他鎖

從鎖的互斥性來看,行級鎖分為共享鎖和排他鎖,它們的兼容關系是理解鎖沖突的基礎。

1、共享鎖(Shared Lock, S Lock):也稱為“讀鎖”。

作用:允許多個事務同時讀取同一行數據。

互斥性:一個事務持有共享鎖后,其他事務可以繼續(xù)加共享鎖來讀取數據,但不能加排他鎖來修改數據

加鎖方式:使用 SELECT … LOCK IN SHARE MODE;或 SELECT … FOR SHARE;

2、排他鎖(Exclusive Lock, X Lock):也稱為“寫鎖”。

使用 SELECT … FOR UPDATE;顯式加鎖。

自動加鎖:UPDATE, DELETE, INSERT語句會自動對其操作的記錄加排他鎖。

作用:允許一個事務讀寫某行數據。

互斥性:一個事務持有排他鎖后,其他事務不能再對該行加任何類型的鎖(包括共享鎖和其他排他鎖),直到該鎖被釋放。

加鎖方式:

它們的兼容關系可以總結為下表:

行鎖的底層實現(xiàn)和特性

行鎖基于索引實現(xiàn)

這是理解行鎖最核心的一點。InnoDB 的行鎖是加在索引項上的,而不是直接加在物理數據行上的。這意味著:

  • 有效使用行鎖的前提:你的 WHERE條件必須能夠有效命中索引。
  • 否則退化為表鎖:如果查詢條件不能使用索引,MySQL 將進行全表掃描,從而對所有記錄加鎖,實際效果等同于鎖住了整個表,會嚴重降低并發(fā)性能

兩階段鎖協(xié)議(Two-Phase Locking, 2PL)

InnoDB 遵循此協(xié)議,鎖的操作分為兩個階段:

  • 加鎖階段:在事務執(zhí)行過程中,根據需要逐步獲取鎖。
  • 解鎖階段:直到事務提交(COMMIT)或回滾(ROLLBACK)時,一次性釋放所有在該事務中獲取的鎖。

重要提示:由于鎖是在事務結束后才釋放,為了減少鎖沖突和提高并發(fā)性,應盡量將最可能引起沖突的寫操作(如 SELECT … FOR UPDATE)放在事務的后面執(zhí)行,以縮短排他鎖的持有時間。

意向鎖(Intention Locks)

意向鎖是表級鎖,用于快速判斷表內是否有被鎖定的行,從而避免為了檢查行鎖而需要遍歷每一行的低效操作。

  • 意向共享鎖(IS):表示事務準備在表中的某些行上加共享鎖。
  • 意向排他鎖(IX):表示事務準備在表中的某些行上加排他鎖。意向鎖之間是兼容的(例如,多個事務可以同時對一個表持有 IX 鎖),但
    它們與表級共享鎖(S)和排他鎖(X)存在互斥關系。意向鎖由 InnoDB 自動管理,無需用戶干預

行鎖類型可視化

理解行鎖的關鍵在于區(qū)分其三種基本類型。下圖通過一個數據索引的例子,清晰展示了三種鎖的鎖定范圍差異,這是理解所有高級鎖概念的基礎。

圖解說明:

  • 記錄鎖(Record Lock):像一把鑰匙只鎖一個特定的座位(如id=10)。它確保在更新或刪除某條確切存在的記錄時,其他事務無法修改或刪除它。
  • 間隙鎖(Gap Lock):鎖住的是座位與座位之間的“空檔”(如(10, 15))。它的存在僅僅是為了防止插入(防止幻讀),但不會阻止其他事務修改這個區(qū)間內已存在的記錄(例如,如果id=12存在,你仍然可以修改它)。
  • 臨鍵鎖(Next-Key Lock):這是 InnoDB 在可重復讀(RR)隔離級別下默認的鎖算法。它是記錄鎖和間隙鎖的結合,鎖定一個左開右閉的區(qū)間。例如,(5, 10]意味著它鎖定了id=10這條記錄,也鎖定了5到10之間的間隙。這能有效防止在10之前插入新數據(解決幻讀),同時保護10這條記錄本身。

以下通過示例和場景進一步解釋這三種鎖。

記錄鎖(Record Lock)

它鎖住的是索引項。例如,執(zhí)行 SELECT * FROM users WHERE id = 10 FOR UPDATE;會在 id=10這個索引項上加一個排他型的記錄鎖,防止其他事務修改或刪除這行數據。

間隙鎖(Gap Lock)

它鎖住的是索引項之間的“空隙”,以防止其他事務在這個空隙中插入新數據,從而解決“幻讀”問題。

間隙鎖只在可重復讀(REPEATABLE READ)及以上隔離級別生效

示例:假設一張表 users的 id字段有值 5, 10, 15。

事務 A 執(zhí)行:SELECT * FROM users WHERE id BETWEEN 10 AND 15 FOR UPDATE;

它不僅會鎖住 id=10和 15的記錄,還會鎖住它們之間的間隙 (10, 15)。
此時事務 B 嘗試執(zhí)行 INSERT INTO users (id) VALUES (12);會被阻塞,因為 12落在了被鎖定的間隙內。

臨鍵鎖(Next-Key Lock)

它是 InnoDB 在可重復讀(REPEATABLE READ)隔離級別下默認使用的鎖算法。

它相當于一個 記錄鎖 + 間隙鎖,鎖定一個左開右閉的區(qū)間 (previous_index, current_index]。

示例:同樣對于 id值為 5, 10, 15 的表。

事務 A 執(zhí)行:SELECT * FROM users WHERE id > 10 FOR UPDATE;

它可能鎖住的區(qū)間包括 (10, 15]和 (15, +∞)。

這既防止了在 (10, 15)區(qū)間內插入新的 id=12,也防止了修改或刪除 id=15的現(xiàn)有記錄,同時還防止了插入任何大于 15 的新 ID。

死鎖與最佳實踐

死鎖是如何產生的呢?

行級鎖雖然提升了并發(fā)度,但也帶來了死鎖的風險。當兩個或多個事務互相等待對方釋放鎖時,就會形成死鎖。

理解 MySQL 中事務的加鎖流程以及死鎖如何形成,是構建高并發(fā)應用的基石。

下面我們通過一個清晰的流程圖來展示一個安全的事務加鎖/解鎖全過程,然后深入剖析幾種典型的死鎖場景。

事務加鎖與解鎖完成流程

首先要明確一個核心概念:兩階段鎖協(xié)議。它規(guī)定鎖的操作分為兩個階段:

1、加鎖階段:在事務執(zhí)行過程中,根據需要逐步獲取鎖。

2、解鎖階段:直到事務提交(COMMIT)或回滾(ROLLBACK)時,一次性釋放所有在該事務中獲取的鎖。

下面的序列圖清晰地展示了一個安全、無沖突的事務加鎖與解鎖流程。

流程解讀:

加鎖:事務 A 首先開啟事務,然后執(zhí)行一條 SELECT … FOR UPDATE語句,意圖鎖定某行數據(例如行 1)進行更新。此時,它會向鎖管理器申請該行的排他鎖(X Lock)

執(zhí)行:成功獲得鎖后,事務 A 可以安全地執(zhí)行修改操作。在此期間,其他事務(如事務 B)如果嘗試獲取同一行的排他鎖或共享鎖,都會被阻塞。

解鎖:當事務 A 提交(COMMIT)后,進入解鎖階段,一次性釋放它持有的所有鎖。

后續(xù):鎖被釋放后,之前被阻塞的事務 B 會被喚醒,并獲得它所需要的鎖,繼續(xù)執(zhí)行。

這個流程是理想狀態(tài)下的。但當多個事務并發(fā)執(zhí)行且鎖的獲取順序出現(xiàn)環(huán)狀依賴時,死鎖就發(fā)生了。

典型死鎖場景詳解

這個流程是理想狀態(tài)下的。但當多個事務并發(fā)執(zhí)行且鎖的獲取順序出現(xiàn)環(huán)狀依賴時,死鎖就發(fā)生了。

場景 1:共享鎖升級導致的死鎖

這是非常經典的死鎖情況,常發(fā)生在先讀后寫的業(yè)務邏輯中。

死鎖形成:

在 T3 時刻,事務 A 需要事務 B 釋放 S 鎖才能升級。

在 T4 時刻,事務 B 需要事務 A 釋放 S 鎖才能升級。

雙方互相等待,形成循環(huán)等待,死鎖產生。

場景 2:順序交叉訪問導致的死鎖

當多個事務以不同的順序訪問和鎖定資源時,極易發(fā)生死鎖。

死鎖形成:

事務 A 在等待事務 B 釋放 id=2 的鎖。

事務 B 在等待事務 A 釋放 id=1 的鎖。

循環(huán)等待再次形成,死鎖發(fā)生。

場景 3:Gap 鎖沖突導致的死鎖

在可重復讀(REPEATABLE READ)隔離級別下,MySQL 會使用間隙鎖(Gap Lock)來防止幻讀,這也可能引發(fā)更復雜的死鎖。

假設 accounts表 id 有 1, 5, 10 三個值,存在間隙 (1,5), (5,10)。

死鎖形成:

事務 A 的插入在等待事務 B 釋放(1,5)間隙上的鎖。

事務 B 的插入在等待事務 A 釋放(1,5)間隙上的鎖。

循環(huán)等待形成,死鎖發(fā)生。

死鎖的處理與預防

nnoDB 存儲引擎內置了死鎖檢測機制。當檢測到死鎖時,它會選擇一個回滾代價較小的事務(通常是影響行數較少的事務)進行回滾,并讓另一個事務繼續(xù)執(zhí)行。

被回滾的事務會收到 ERROR 1213 (40001): Deadlock found錯誤。

核心預防策略

  • 固定訪問順序:在應用設計中,保證所有事務以相同的順序訪問數據行。例如,約定更新賬戶時總是按 id 從小到大處理,可以避免場景二的死鎖
  • 避免在事務中加鎖:如果業(yè)務允許,使用樂觀鎖(如版本號機制)替代悲觀鎖,從根本上減少鎖競爭
  • 保持事務小巧且快速:大事務會長時間持有鎖,增加死鎖概率。應將大事務拆分為小事務
  • 為查詢創(chuàng)建合適的索引:如果查詢條件未使用索引,InnoDB 可能會鎖住更多記錄(甚至全表),大幅增加死鎖風險。
  • 使用較低的隔離級別:如果業(yè)務能接受,將隔離級別設為讀已提交(READ COMMITTED),此級別下 InnoDB 不會使用間隙鎖(Gap Lock),可減少死鎖。

事務的加鎖解鎖遵循“兩階段鎖協(xié)議”,提交或回滾時釋放所有鎖。死鎖的本質是事務間形成了對鎖資源的循環(huán)等待。

通過理解其原理并采用固定的資源訪問順序、使用樂觀鎖、減小事務粒度等預防措施,可以顯著降低死鎖發(fā)生概率。

總結

到此這篇關于MySQL全局鎖、表鎖、行鎖、間隙鎖、臨鍵鎖超詳細講解的文章就介紹到這了,更多相關MySQL全局鎖、表鎖、行鎖、間隙鎖、臨鍵鎖內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • MySQL的緩存策略方式

    MySQL的緩存策略方式

    MySQL緩存方案主要用于減輕數據庫讀寫壓力,通過使用Redis緩存用戶定義的熱點數據,用戶可以直接從緩存中獲取數據,文章還討論了如何通過讀寫分離、連接池和異步連接等技術提升MySQL的訪問性能,此外,還探討了緩存方案中的一致性問題、讀寫策略以及緩存穿透
    2024-09-09
  • Windows下mysql 5.7 設置區(qū)分大小寫(敏感),設置默認編碼 utf8mb4

    Windows下mysql 5.7 設置區(qū)分大小寫(敏感),設置默認編碼 utf8mb4

    最近需要將Windows下的mysql 5.7設置區(qū)分大小寫(敏感),設置默認編碼 utf8mb4,需要的朋友可以參考下
    2022-10-10
  • MySQL中表的內連和外連詳解

    MySQL中表的內連和外連詳解

    文章主要講解內連接與外連接(左、右)的用法,內連接通過WHERE子句篩選笛卡爾積,是開發(fā)中最常用的連接方式;外連接則保留左或右表所有數據,練習涵蓋學生成績與部門員工信息的聯(lián)合查詢應用
    2025-08-08
  • 使用Canal實現(xiàn)MySQL數據同步的完整指南

    使用Canal實現(xiàn)MySQL數據同步的完整指南

    Canal 是阿里巴巴開源的一個基于 MySQL 數據庫增量日志(binlog)解析的組件,本文主要介紹了如何使用Canal實現(xiàn)MySQL數據同步功能,希望對大家有所幫助
    2025-06-06
  • MAC下MYSQL數據庫密碼忘記的解決辦法

    MAC下MYSQL數據庫密碼忘記的解決辦法

    這篇文章主要介紹了Mac操作系統(tǒng)下MYSQL數據庫密碼忘記的快速解決辦法,教大家重置MYSQ密碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • mysql中日期的加減 date_add()、date_sub() 函數及用法小結

    mysql中日期的加減 date_add()、date_sub() 函數及用法小結

    在Mysql中,date_add與date_sub分別是指對于日期的一個加減操作,date_add是指從日期中加上指定的時間間隔,date_sub是指從日期中減去指定的時間間隔,本文通過實例講解mysql中日期的加減 date_add()、date_sub() 函數及用法小結,感興趣的朋友一起看看吧
    2023-11-11
  • mysql中json類型字段的基本用法實例

    mysql中json類型字段的基本用法實例

    大家應該都知道m(xù)ysql中的字段可以使用json的格式來進行存儲,下面這篇文章主要給大家介紹了關于mysql中json類型字段的基本用法,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-08-08
  • MySQL數據庫如何克隆(帶腳本)

    MySQL數據庫如何克隆(帶腳本)

    這篇文章主要介紹了MySQL數據庫如何克隆(帶腳本)問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • SQL中l(wèi)imit函數語法與用法(MYSQL獲取限制某行數據)

    SQL中l(wèi)imit函數語法與用法(MYSQL獲取限制某行數據)

    limit是MySql的內置函數,一般用于查詢表中記錄的條數,作用是用于限制查詢條數,下面這篇文章主要給大家介紹了關于SQL中l(wèi)imit函數語法與用法的相關資料,詳細講了MYSQL獲取限制某行數據的方法,需要的朋友可以參考下
    2022-08-08
  • Mysql中Table ‘XXX’ is marked as crashed and last (automatic?)問題解決方法

    Mysql中Table ‘XXX’ is marked as crashed and last (automatic?)

    這篇文章主要介紹了Mysql中Table ‘XXX’ is marked as crashed and last (automatic?)問題解決方法,需要的朋友可以參考下
    2014-05-05

最新評論

遂宁市| 东平县| 南乐县| 平果县| 怀化市| 香格里拉县| 永靖县| 浑源县| 西平县| 隆昌县| 龙岩市| 隆德县| 都江堰市| 博白县| 高要市| 利川市| 永丰县| 元江| 江西省| 兴文县| 慈溪市| 封丘县| 彭泽县| 赫章县| 介休市| 西林县| 旌德县| 炉霍县| 安仁县| 商丘市| 莱西市| 屯昌县| 鸡泽县| 滨州市| 阿拉尔市| 江川县| 泸溪县| 抚宁县| 东辽县| 扎赉特旗| 凤冈县|