MySQL 鎖的相關知識 | lock與latch、鎖的類型、簡談MVCC、鎖算法、死鎖、鎖升級

文章目錄

  • lock與latch
  • 鎖的類型
  • MVCC
    • 一致性非鎖定讀(快照讀)
    • 一致性鎖定讀(當前讀)
  • 鎖算法
  • 死鎖
  • 鎖升級


lock與latch

在了解數據庫鎖之前,首先就要區分開 locklatch。在數據庫中,locklatch 雖然都是鎖,卻有著截然不同的含義。

  • latch 通常被我們稱為閂鎖(輕量級鎖),因為其要求鎖定的時間必須非常短。在 InnoDB 中,latch 可以分為 mutex(互斥鎖)rwlock(讀寫鎖) ,它的作用是用來保證并發線程操作臨界資源的正確性,并且通常沒有死鎖檢測機制

  • lock 的操作對象則是事務,用來鎖定數據庫中的對象,如表、頁、行等,一般 lock 的對象僅在事務提交或者回滾后釋放,lock 有死鎖檢測機制

關于數據庫頁結構的詳細內容可以看這篇博客
在這里插入圖片描述


鎖的類型

InnoDB存儲引擎 中實現了下面兩種標準的行級鎖:

  • 共享鎖(S Lock) : 允許事務讀一行數據
  • 排他鎖(X Lock) : 允許事務刪除或者更新一行數據。

由于共享鎖并不涉及到數據的修改,所以即使一個事務已經獲得了某行的共享鎖,另外的事務也可以立即獲得該行的共享鎖,這種情況又被稱為鎖兼容

對于排他鎖又是另一種情況,由于排他鎖涉及到了數據的修改,為了保證安全,其他的事務想要獲得同一行的排他鎖時,必須要等到前一個事務釋放鎖才行,這種情況又被稱為鎖不兼容

下面是排他鎖和共享鎖的兼容性:
在這里插入圖片描述

由于 InnoDB 支持多粒度鎖定,所以允許事務可以同時存在行鎖和表鎖,為了支持在不同粒度上進行加鎖操作,InnoDB 支持一種額外的鎖方式,即 意向鎖(Intention Lock)。意向鎖即將鎖定的對象分為多個層次,意味著希望事務在更細粒度上進行加鎖。

如果我們想對下層的對象(如記錄【一行就是一個記錄】)上一個 X鎖 ,就需要先對粒度更粗的上層對象上鎖,需要分別先對數據庫、表、頁上 意向排他鎖(IX鎖) ,再對記錄上 X鎖 。(如果沒有意向鎖,我們對一行上了讀鎖之后,假如某個事務申請了一個表級的寫鎖,此時這個事務就會對我們上鎖的數據進行修改。)

PS:讀/寫鎖共享/排他鎖 的一種。
在這里插入圖片描述
InnoDB 支持意向鎖設計比較簡練,其意向鎖即為表級別的鎖,意向鎖主要是為了在一個事務中揭示下一行將被請求的鎖的類型,兩種意向鎖分別如下:

  • 意向共享鎖(IS Lock),事務要想獲得某一張表中某幾行的共享鎖。
  • 意向排他鎖(IX Lock),事務要想獲得某一張表中某幾行的排他鎖。

由于 InnoDB 支持的是行級別的鎖,因此意向鎖不會阻塞 除全表掃描外 的任何請求,故兼容性如下:

在這里插入圖片描述


MVCC

MVCC(Multi-Version Concurrency Control)即多版本并發控制,是數據庫并發控制的一種方法

一致性非鎖定讀(快照讀)

如果我們讀取的行正在執行 DELETE 或者 UPDATE 操作,這時就不會去等待鎖釋放后再讀取,而是直接去讀取行的一個快照數據,如下圖所示:
在這里插入圖片描述

快照數據指的是該行之前版本的數據,這些數據存儲在 undo段 中,由于 undo 用來在事務中回滾數據,因此這些快照數據本身并沒有額外的開銷。并且我們只是讀操作,并不涉及修改,而且也沒有事務會去對歷史數據進行修改,所以在讀取快照數據的時候不需要進行加鎖。

快照讀機制讓讀取操作不再占用和等待表上的鎖,極大的提高了數據庫的性能。但由于每個快照都相當于是一個歷史版本,行的多版本需要并發控制—— MVCC

需要注意的是,MVCC 只在 READ COMMITTED(讀已提交)REPEATABLE READ(可重復讀)兩個隔離級別下工作。由于 READ UNCOMMITTED(讀未提交) 總會讀取最新的數據,而 SERIALIZABLE(可串行化) 會對所有讀取的行加鎖,所以這兩種都不兼容 MVCC

  • RC 隔離級別下,是每個快照讀都會生成并獲取最新的 Read View,也就是同一個事務中每次快照讀的結果都不一樣
  • RR 隔離級別下,則是同一個事務中的第一個快照讀才會創建 Read View, 之后的快照讀獲取的都是同一個 Read View ,也就是同一個事務中每次快照讀的結果都跟第一次快照讀一樣

當前讀,快照讀和MVCC的關系

  • MVCC 多版本并發控制是 「維持一個數據的多個版本,使得讀寫操作沒有沖突」 的概念,只是一個抽象概念,并非實現。
  • MVCC 只是一個抽象概念,MySQL 需要提供具體的功能去實現它,「快照讀就是 MySQL 實現了 MVCC 理想模型的其中一個功能——非阻塞讀」。而相對而言,當前讀就是悲觀鎖的具體功能實現。
  • 要說的再細致一些,快照讀本身也是一個抽象概念,再深入研究。MVCC 模型在 MySQL 中的具體實現則是由 3 個隱式字段undo 日志Read View 等去完成的。

更多MVCC知識可以閱讀這篇博客


一致性鎖定讀(當前讀)

一致性鎖定讀又稱為當前讀,讀取的是行的最新版本,并且讀取的時候為了防止其他事務修改當前行,還會對當前行進行加鎖。

InnoDB 中,對于 SELECT語句 支持以下兩種一致性鎖定讀操作:

  • SELECT…FOR UPDATE(排他鎖) :會對讀取的行加一個排他鎖,此時其他事務不能對該行上任何鎖。
  • SELECT…LOCK IN SHARE MODE(共享鎖) :會位讀取的行加上一個共享鎖,此時其余的事務可以對該行加上共享鎖,但是如果想加排他鎖,則會被阻塞。

鎖算法

InnoDB 中有三種行鎖的算法:

  • Record Lock(記錄鎖): 單個行記錄上的鎖。
  • Gap Lock(間隙鎖) : 鎖定一個范圍,但不包含記錄本身。
  • Next-Key Lock(下一鍵鎖) : 前兩種鎖的結合,既鎖定一個范圍,也鎖定記錄本身。

舉例:

有一組數據,其索引分別為 10、30、60 ,此時使用 SQL 語句 SELECT * FROM t WHERE id = 10 FOR UPDATE ,三種鎖的范圍如下

  • Record: 對10單行進行加鎖
  • Gap Lock : (-∞, 10)、(10, 30)、(30, 60)、(60, +∞)
  • Next-Key Lock: (-∞,10]、(10,30]、(30,60]、(60,+∞)

對于 Record Lockl 來說,其總是會去鎖住索引記錄,即使沒有設置任何一個索引,它也會使用隱式的索引進行鎖定。

Next-Key Lock 是 結合了前面所說的兩種鎖算法,既鎖住范圍,也鎖住記錄本身,在 InnoDB 中對于行的查詢都會采用這種算法,而設計它的目的正是為了解決幻讀問題。

幻讀指 在同一事務中,用同樣的操作讀取兩次,得到的記錄數卻不一樣(針對同一個范圍的數據)。 主要原因就是當第一個事務對表中的所有數據行進行修改;同時,第二個事務向表中插入了一行。這樣也就導致了操作第一個事務的用戶發現表中還有沒修改的數據行,像發生了幻覺一樣。

在這里插入圖片描述
明明在 會話A 的第一次查詢中,大于 2 的數只有行只有一行,而由于 會話B 插入了新行后,對于 會話A 而言就憑空多出來了一行,像出現了幻覺一樣。

對于以上數據,Next-Key Locking算法SELECT * FROM t WHERE a > 2 FOR UPDATE 這條語句中,鎖住的不僅僅是 5 這個數值,而是對直接對[2,+∞) 這個范圍加了排他鎖,所以任何對于這個范圍的插入都不能進行,也就避免了幻讀現象的發生。

同理,間隙鎖 Gap Lock 也是鎖定某個范圍,所以它也能防止幻讀的出現。

InnoDB 正是借助 鎖(Gap Lock、Next-Key Lock) 以及 MVCC(快照讀) 這兩個機制實現了事務的隔離性


死鎖

死鎖指的是兩個或者兩個以上的事務在執行過程中,因為爭搶所資源而導致的一種互相等待的現象。在死鎖的情況下,如果沒有外力作用,事務將永遠無法推進下去。

在數據庫中通常都會使用超時機制來解決死鎖:為事務設置超時時間,當其中一方超時后立刻進行回滾,另一個事務就能夠繼續進行了。

雖然超時機制可以解決這個問題,但是我們并不能掌握回滾的事務的量級,倘若事務更新龐大,則回滾就會帶來大量的性能損耗,所以我們通常會采用更加主動的策略,即使用等待圖來進行死鎖檢測:

在這里插入圖片描述

  • 圖中每個節點即為一個事務。
  • 每條指向其他節點的線則代表著正在等待該節點的資源。
  • 當存在回路時,則代表著事務互相等待,此時就意味著存在死鎖。

每當事務請求鎖并發生等待時,都會主動判斷等待圖中是否存在回路,如果存在則代表著有死鎖產生,此時就會主動選擇 undo量最小的事務 來打破死鎖。在現版本的 InnoDB 中,通常采用 深度優先搜索(老版本使用遞歸) 來檢測死鎖的存在。


鎖升級

在數據庫為了保證安全,大量的并發下必定存在著大量的鎖,但鎖是一種稀有資源,為了避免大量鎖的開銷,數據庫中存在著鎖升級的機制。

鎖升級指的是將當前的鎖升級為更粗粒度的鎖 例如我們可以將多個行鎖升級為一個頁鎖,又或者將多個頁鎖升級為一個表鎖。這種升級減少了鎖的數量、保護了系統資源,防止系統使用太多內存來維護大量的鎖,在一定程度上提高了效率。

SQL Server 中,鎖升級是很常見的現象,當滿足以下條件中其中一個時則會進行鎖升級:

  • 鎖資源占用的內存超過了激活內存的 40%
  • 一條單獨的 SQL語句 在一個對象上持有的鎖數量超過了閾值,閾值默認為 5000

而在 MySQLInnoDB 中,則不存在鎖升級的問題。其根據每個事務訪問的每個頁對鎖進行管理,并且使用位圖來標記,所以一個事務無論鎖住頁中多少條記錄,開銷都相同。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/443747.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/443747.shtml
英文地址,請注明出處:http://en.pswp.cn/news/443747.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Hibernate使用原生SQL適應復雜數據查詢

HQL盡管容易使用,但是在一些復雜的數據操作上功能有限。特別是在實現復雜的報表統計與計算,以及多表連接查詢上往往無能為力,這時可以使用SQL(Native SQL)實現HQL無法完成的任務。 1、使用SQL查詢 使用SQL查詢可以通過…

MySQL 存儲引擎 | MyISAM 與 InnoDB

文章目錄概念innodb引擎的4大特性索引結構InnoDBMyISAM區別表級鎖和行級鎖概念 MyISAM 是 MySQL 的默認數據庫引擎(5.5版之前),但因為不支持事務處理而被 InnoDB 替代。 然而事物都是有兩面性的,InnoDB 支持事務處理也會帶來一些…

MySQL 事務 | ACID、四種隔離級別、并發帶來的隔離問題、事務的使用與實現

文章目錄事務ACID并發帶來的隔離問題幻讀(虛讀)不可重復讀臟讀丟失更新隔離級別Read Uncommitted (讀未提交)Read Committed (讀已提交)Repeatable Read (可重復讀)Serializable (可串行化)事務的使用事務的實現Redoundo事務 事務指邏輯上的一組操作。 …

MySQL 備份與主從復制

文章目錄備份主從復制主從復制的作用備份 根據備份方法的不同,備份可劃分為以下幾種類型: 熱備(Hot Backup) : 熱備指的是在數據庫運行的時候直接備份,并且對正在運行的數據庫毫無影響,這種方法在 MySQL 官方手冊中又…

C++ 流的操作 | 初識IO類、文件流、string流的使用

文章目錄前言IO頭文件iostreamfstreamsstream流的使用不能拷貝或對 IO對象 賦值條件狀態與 iostate 類型輸出緩沖區文件流fstream類型文件模式文件光標函數tellg() / tellp()seekg() / seekp()向文件存儲內容/讀取文件內容string流istringstreamostringstream前言 我們在使用 …

Hibernate 更新部分更改的字段 hibernate update

Hibernate 中如果直接使用 Session.update(Object o);或則是Session.updateOrUpdate(Object o); 會把這個表中的所有字段更新一遍。 如: ExperClass4k e new ExperClass4k(); e.setTime(time); e.setQ_num(q_num); e.setK(k); if (str "finch_fix")…

C++ 類的行為 | 行為像值的類、行為像指針的類、swap函數處理自賦值

文章目錄概念行為像值的類行為像指針的類概念引用計數動態內存實現計數器類的swap概念swap實現自賦值概念 行為像值的類和行為像指針的類這兩種說法其實蠻拗口的,這也算是 《CPrimer》 翻譯的缺點之一吧。。。 其實兩者的意思分別是: 行為像值的類&am…

C++ 右值引用 | 左值、右值、move、移動語義、引用限定符

文章目錄C11為什么引入右值?區分左值引用、右值引用move移動語義移動構造函數移動賦值運算符合成的移動操作小結引用限定符規定this是左值or右值引用限定符與重載C11為什么引入右值? C11引入了一個擴展內存的方法——移動而非拷貝,移動較之拷…

且談關于最近軟件測試的面試

前段時間有新的產品需要招人,安排和參加了好幾次面試,下面就談談具體的面試問題,在面試他人的同時也面試自己。 面試問題是參與面試同事各自設計的,我也不清楚其他同事的題目,就談談自己設計的其中2道題。 過去面試總是…

C++ 多態 | 虛函數、抽象類、虛函數表

文章目錄多態虛函數重寫重定義(參數不同)協變(返回值不同)析構函數重寫(函數名不同)final和override重載、重寫、重定義抽象類多態的原理虛函數常見問題解析虛函數表多態 一種事物,多種形態。換…

C++ 運算符重載(一) | 輸入/輸出,相等/不等,復合賦值,下標,自增/自減,成員訪問運算符

文章目錄輸出運算符<<輸入運算符>>相等/不等運算符復合賦值運算符下標運算符自增/自減運算符成員訪問運算符輸出運算符<< 通常情況下&#xff0c;輸出運算符的第一個形參是一個 非常量ostream對象的引用 。之所以 ostream 是非常量是因為向流寫入內容會改變…

C++ 重載函數調用運算符 | 再探lambda,函數對象,可調用對象

文章目錄重載函數調用運算符lambdalambda等價于函數對象lambda等價于類標準庫函數對象可調用對象與function可調用對象function函數重載與function重載函數調用運算符 函數調用運算符必須是成員函數。 一個類可以定義多個不同版本的調用運算符&#xff0c;互相之間應該在參數數…

C++ 運算符重載(二) | 類型轉換運算符,二義性問題

文章目錄類型轉換運算符概念避免過度使用類型轉換函數解決上述問題的方法轉換為 bool顯式的類型轉換運算符類型轉換二義性重載函數與類型轉換結合導致的二義性重載運算符與類型轉換結合導致的二義性類型轉換運算符 概念 類型轉換運算符&#xff08;conversion operator&#…

Tomcat中JVM內存溢出及合理配置

Tomcat本身不能直接在計算機上運行&#xff0c;需要依賴于硬件基礎之上的操作系統和一個Java虛擬機。Tomcat的內存溢出本質就是JVM內存溢出&#xff0c;所以在本文開始時&#xff0c;應該先對Java JVM有關內存方面的知識進行詳細介紹。 一、Java JVM內存介紹 JVM管理兩種類型的…

俄羅斯農民乘法 | 快速乘

文章目錄概念概念 俄羅斯農民乘法經常被用于兩數相乘取模的場景&#xff0c;如果兩數相乘已經超過數據范圍&#xff0c;但取模后不會超過&#xff0c;我們就可以利用這個方法來拆位取模計算貢獻&#xff0c;保證每次運算都在數據范圍內。 A 和 B 兩數相乘的時候我們如何利用加…

Linux網絡編程 | socket選項設定 及 網絡信息API

文章目錄讀取和設置 socket 選項SO_REUSEADDRSO_RCVBUF 和 SO_SNDBUFSO_RCVLOWAT 和 SO_SNDLOWATSO_LINGER 選項網絡信息APIgethostbyname 和 gethostbyaddrgetservbyname 和 getservbyportgetaddrinfogetnameinfo讀取和設置 socket 選項 正如 fcntl 系統調用是控制文件描述符…

Linux | 高級I/O函數

文章目錄創建文件描述符的函數pipe函數dup函數、dup2函數讀取或寫入數據readv函數、writev函數零拷貝sendfile函數splice函數tee函數進程間通信——共享內存mmap函數 和 munmap函數控制文件描述符fcntl函數創建文件描述符的函數 pipe函數 不再贅述&#xff0c;詳情見我的另一…

分布式理論:CAP、BASE | 分布式存儲與一致性哈希

文章目錄分布式理論CAP定理BASE理論分布式存儲與一致性哈希簡單哈希一致性哈希虛擬節點分布式理論 CAP定理 一致性&#xff08;Consistency&#xff09;&#xff1a; 在分布式系統中的所有數據副本&#xff0c;在同一時刻是否一致&#xff08;所有節點訪問同一份最新的數據副…

Tomcat服務器性能優化

一、概述 本文檔主要介紹了Tomcat的性能調優的原理和方法。可作為公司技術人員為客戶Tomcat系統調優的技術指南&#xff0c;也可以提供給客戶的技術人員作為他們性能調優的指導手冊。 二、調優分類 由于Tomcat的運行依賴于JVM&#xff0c;從虛擬機的角度我們把Tomcat的調整分為…

分布式系統概念 | 分布式事務:2PC、3PC、本地消息表

文章目錄分布式事務2PC&#xff08;二階段提交協議&#xff09;執行流程優缺點3PC&#xff08;三階段提交協議&#xff09;執行流程優缺點本地消息表&#xff08;異步確保&#xff09;分布式事務 分布式事務就是指事務的參與者、支持事務的服務器、資源服務器以及事務管理器分…