數據庫中的六大鎖

目錄

一、死鎖

二、鎖的區間劃分

1、間隙鎖(Gap Locks)

2、臨鍵鎖(Next-key Locks)

三、鎖的粒度劃分

1、表級鎖(Table-level lock)

2、行級鎖(Record Locks)

3、頁級鎖

四、鎖級別劃分

1、共享鎖(share lock,即S鎖)

2、排它鎖 / 獨占鎖(exclusive lock,即X鎖)

3、意向鎖

五、加鎖方式分類

1、自動鎖( Automatic Locks)

2、顯示鎖(LOCK TABLES )

六、鎖的使用方式分類

1、樂觀鎖(Optimistic Lock)

2、悲觀鎖(Pessimistic Lock)

總結


鎖是計算機協調多個進程或線程并發訪問某一個資源的機制,在數據庫中,除傳統的計算資源(CPU、RAM、I/O)的爭用以外,數據也是一種供許多用戶共享的資源。如何保證數據并發訪問的一致性、有效性是所在有數據庫必須解決的一個問題,鎖沖突也是影響數據庫并發訪問性能的一個重要因素。從這個角度來說,鎖對數據庫而言顯得尤其重要,也更加復雜。

一、死鎖

講述之前先簡單介紹第一個鎖:死鎖
如下表

CREATE TABLE `test` (`id` int(20) NOT NULL,`name` varchar(20) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

表中數據有:

mysql> SELECT * FROM test;
+----+------+
| id | name |
+----+------+
|  1 | 1    |
|  5 | 5    |
+----+------+
6 rows in set (0.00 sec)

兩個事務對一個表進行如下操作

session1										 	session2
begin;										 	 	begin;select * from test where id = 3 for update;     	select * from test where id = 4 for update;insert into test(id, name) values(3, "test1");    insert into test(id, name) values(4, "test2");鎖等待中
鎖等待解除死鎖,session 2的事務被回滾


上面兩個并發事務一定會發生死鎖(這里之所以限定RR和Serializable兩個隔離級別,是因為只有這兩個級別下才會有間隙鎖/臨鍵鎖,而這是導致死鎖的根本原因)。
select … for update雖然可以用于解決數據庫的并發操作,但在實際項目中卻不建議使用,原因是當查詢條件對應的記錄不存在時,很容易造成死鎖。而造成死鎖的原因和MySQL的鎖機制有關。

二、鎖的區間劃分

1、間隙鎖(Gap Locks)

實例: (3, 4)
間隙鎖是開區間的,是一個在索引記錄之間的間隙上的鎖。
作用:保證某個間隙內的數據在鎖定情況下不會發生任何變化。比如我mysql默認隔離級別下的可重復讀(RR)。
當使用唯一索引來搜索唯一行的語句時,不需要間隙鎖定。如下面語句的id列有唯一索引,此時只會對id值為10的行使用記錄鎖。

select * from t where id = 10 for update;// 注意:普通查詢是快照讀,不需要加鎖

如果,上面語句中id列沒有建立索引或者是非唯一索引時,則語句會產生間隙鎖。

如果,搜索條件里有多個查詢條件(即使每個列都有唯一索引),也是會有間隙鎖的。
根據檢索條件向下尋找最靠近檢索條件的記錄值A作為左區間,向上尋找最靠近檢索條件的記錄值B作為右區間,即鎖定的間隙為(A,B),并且,不允許其他區間進行修改的值為查詢的值

2、臨鍵鎖(Next-key Locks)

臨鍵鎖是行鎖+間隙鎖,即臨鍵鎖是是一個左開右閉的區間,比如(- ∞, 1 ] |(1, 3 ] |(3, 4 ] | (4, + ∞)。
InnoDB的默認事務隔離級別是RR,在這種級別下,如果使用select … in share mode或者select … for update語句,那么InnoDB會使用臨鍵鎖,因而可以防止幻讀;但即使你的隔離級別是RR,如果你這是使用普通的select語句,那么InnoDB將是快照讀,不會使用任何鎖,因而還是無法防止幻讀。

三、鎖的粒度劃分

1、表級鎖(Table-level lock)

直接給整個表添加鎖:

select * from student where name = 'tom' for update

InnoDB在使用過程中只要不通過索引檢索數據時,全部是表鎖。
開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖沖突的概率最高,并發度最低
MyISAM在執行查詢語句(SELECT)前,會自動給涉及的所有表加讀鎖,在執行更新操作(UPDATE、DELETE、INSERT等)前,會自動給涉及的表加寫鎖,這個過程并不需要用戶干預,因此用戶一般不需要直接用LOCK TABLE命令給MyISAM表顯式加鎖。

2、行級鎖(Record Locks)

InnoDB中給指定的行添加鎖:

select * from student where id > 10 for update
1
InnoDB行鎖是通過給索引上的索引項加鎖來實現的,這一點,MySQL于Oracle不同,后者是通過在數據塊中對相應的數據行加鎖來實現的,InnoDB只有通過索引條件檢索數據,InnoDB才使用行級鎖
行鎖的劣勢:開銷大;加鎖慢;會出現死鎖
行鎖的優勢:鎖的粒度小,發生鎖沖突的概率低;處理并發的能力強

3、頁級鎖

頁級鎖是 MySQL 中比較獨特的一種鎖定級別,在其他數據庫管理軟件中并不常見。
頁級鎖的顆粒度介于行級鎖與表級鎖之間,所以獲取鎖定所需要的資源開銷,以及所能提供的并發處理能力同樣也是介于上面二者之間。另外,頁級鎖和行級鎖一樣,會發生死鎖。
頁級鎖主要應用于 BDB 存儲引擎。

四、鎖級別劃分

1、共享鎖(share lock,即S鎖)

共享鎖(S):又稱讀鎖,允許一個事務去讀取一行,阻止其他事務獲得相同數據集的排它鎖,若事務T對數據對象A加上S鎖,則事務T可以讀A,但不能修改A,其他事務只能對再對A加S鎖,而不能加X鎖,直到T釋放A上的鎖,這保證了其他事務可以讀A,但在釋放A上的S鎖之前不能對A做任何修改。

2、排它鎖 / 獨占鎖(exclusive lock,即X鎖)

排它鎖(X):又稱寫鎖,允許獲取排它鎖的事物更新數據,阻止其他事務取得相同的數據集共享讀鎖和排它寫鎖,若事務T對數據對象A加上X鎖,事物T可以讀A也可以修改A,其他事務不能再對A加任何鎖,直到T 釋放A上的鎖

3、意向鎖

事物B對一行數據使用行鎖,當有另一個事物A對這個表使用了表鎖,那么這個行鎖就會升級為表鎖,事務A在申請行鎖(寫鎖)之前,數據庫會自動先給事務A申請表的意向排他鎖。當事務B去申請表的寫鎖時就會失敗,因為表上有意向排他鎖之后事務B申請表的寫鎖時會被阻塞。
當一個事務在需要獲取資源的鎖定時,如果該資源已經被排他鎖占用,則數據庫會自動給該事務申請一個該表的意向鎖。如果自己需要一個共享鎖定,就申請一個意向共享鎖。如果需要的是某行(或者某些行)的排他鎖定,則申請一個意向排他鎖。

五、加鎖方式分類

1、自動鎖( Automatic Locks)

當進行一項數據庫操作時,缺省情況下,系統自動為此數據庫操作獲得所有有必要的鎖。

自動鎖分為三種:
DML 鎖:

  • 鎖用于控制并發事務中的數據操縱,保證數據的一致性和完整性。
  • 保護并發情況下的數據完整性。
  • 語句能夠自動地獲得所需的表級鎖(TM)與行級(事務)鎖(TX)。

DDL 鎖:

  • 鎖用于保護數據庫對象的結構,如表、索引等的結構定義。

排它 DDL 鎖

  • 創建、修改、刪除一個數據庫對象的 DDL 語句獲得操作對象的 排它鎖。

共享 DDL 鎖

  • 需在數據庫對象之間建立相互依賴關系的 DDL 語句通常需共享獲得 DDL鎖。
  • 如創建一個包,該包中的過程與函數引用了不同的數據庫表,當編譯此包時該事務就獲得了引用表的共享 DDL 鎖。如使用 alter table 語句時,為了維護數據的完成性、一致性、合法性,該事務獲得一排它 DDL 鎖

systemlocks。

2、顯示鎖(LOCK TABLES )

某些情況下,需要用戶顯示的鎖定數據庫操作要用到的數據,才能使數據庫操作執行得更好,顯示鎖是用戶為數據庫對象設定的。
(1) LOCK TABLES

LOCK TABLES  tbl_name  read|write, tbl_name read|write, ...UNLOCK TABLES #解開全部的鎖,后面不跟表名


施加寫鎖,寫鎖是排他的,不允許別的線程讀和寫,自己施加鎖是不受影響
(2) FLUSH TABLES:將內存中的數據同步到磁盤上,即刷寫操作,但是這個同步過程可以施加鎖,一旦施加鎖的時候,即執行將對應的表同步,關閉,打開,并施加鎖。一旦施加了鎖,此時別的線程讀操作不受影響,但是寫操作將不能被執行,需要解鎖后才能生效

FLUSH TABLES tbl_name,... [WITH READ LOCK];UNLOCK TABLES;鎖住所有的表,注意,可以針對某張表進行上鎖MariaDB [sunny]> flush tables with read lock;Query OK, 0 rows affected (0.00 sec)其他線程,解鎖后才能夠插入數據MariaDB [sunny]> insert into classlist values ("tracy",2,"99");Query OK, 1 row affected (1 min 5.58 sec)

六、鎖的使用方式分類

1、樂觀鎖(Optimistic Lock)

樂觀鎖的特點先進行業務操作,不到萬不得已不去拿鎖。即“樂觀”的認為拿鎖多半是會成功的,因此在進行完業務操作需要實際更新數據的最后一步再去拿一下鎖就好。
樂觀鎖是否在事務中其實都是無所謂的,其底層機制是這樣:在數據庫內部update同一行的時候是不允許并發的,即數據庫每次執行一條update語句時會獲取被update行的寫鎖,直到這一行被成功更新后才釋放。因此在業務操作進行前獲取需要鎖的數據的當前版本號,然后實際更新數據時再次對比版本號確認與之前獲取的相同,并更新版本號,即可確認這之間沒有發生并發的修改。如果更新失敗即可認為老版本的數據已經被并發修改掉而不存在了,此時認為獲取鎖失敗,需要回滾整個業務操作并可根據需要重試整個過程。

2、悲觀鎖(Pessimistic Lock)

悲觀鎖的特點是先獲取鎖,再進行業務操作,即“悲觀”的認為獲取鎖是非常有可能失敗的,因此要先確保獲取鎖成功再進行業務操作。通常所說的“一鎖二查三更新”即指的是使用悲觀鎖。通常來講在數據庫上的悲觀鎖需要數據庫本身提供支持,即通過常用的select … for update操作來實現悲觀鎖。當數據庫執行select for update時會獲取被select中的數據行的行鎖,因此其他并發執行的select for update如果試圖選中同一行則會發生排斥(需要等待行鎖被釋放),因此達到鎖的效果。select for update獲取的行鎖會在當前事務結束時自動釋放,因此必須在事務中使用。
這里需要注意的一點是不同的數據庫對select for update的實現和支持都是有所區別的,例如oracle支持select for update no wait,表示如果拿不到鎖立刻報錯,而不是等待,mysql就沒有no wait這個選項。另外mysql還有個問題是select for update語句執行中所有掃描過的行都會被鎖上,這一點很容易造成問題。因此如果在mysql中用悲觀鎖務必要確定走了索引,而不是全表掃描。

總結


樂觀鎖在不發生取鎖失敗的情況下開銷比悲觀鎖小,但是一旦發生失敗回滾開銷則比較大,因此適合用在取鎖失敗概率比較小的場景,可以提升系統并發性能

樂觀鎖還適用于一些比較特殊的場景,例如在業務操作過程中無法和數據庫保持連接等悲觀鎖無法適用的地方

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

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

相關文章

一分鐘教你學浪app視頻怎么緩存

你是否在學浪app上苦苦尋找如何緩存視頻的方法?你是否想快速、輕松地觀看自己喜歡的視頻內容?那么,讓我們一起探索一分鐘教你如何緩存學浪app視頻的技巧吧! 學浪下載工具我已經打包好了,有需要的自己下載一下 學浪下…

【JavaScript】ECMAS6(ES6)新特性概覽(二):解構賦值、擴展與收集、class類全面解析

🔥 個人主頁:空白詩 🔥 熱門專欄:【JavaScript】 文章目錄 🌿 引言五、 Destructuring Assignment - 解構賦值,數據提取的藝術 🎨📌 數組解構📌 對象解構📌 特…

動態規劃之單詞拆分

這次分享一道關于動態規劃的leetcode,單詞拆分。 單詞拆分 給你一個字符串 s 和一個字符串列表 wordDict 作為字典。如果可以利用字典中出現的一個或多個單詞拼接出 s 則返回 true。注意:不要求字典中出現的單詞全部都使用,并且字典中的單詞…

【技術】漢諾塔的遞歸問題解析及多語言實現

漢諾塔的遞歸問題解析及多語言實現 漢諾塔(Hanoi Tower)問題是一個非常經典的遞歸問題。它起源于一個古老的傳說:有三個柱子和64個大小不一的金盤,開始時這些金盤按從小到大的順序放在柱子A上,目標是在柱子B上按同樣的…

Java——Java開發環境

一、JDK 1、什么是JDK JDK(Java Development Kit,Java 開發工具包)是用于開發 Java 應用程序的核心工具包。它包含了編寫、編譯、調試和運行 Java 程序所需的一切工具和庫。JDK 是每個 Java 開發者必備的工具。 2、JDK 主要組件 JDK主要包…

HNU-計算機體系結構-實驗3-緩存一致性

計算機體系結構 實驗3 計科210X 甘晴void 202108010XXX 文章目錄 計算機體系結構 實驗31 實驗目的2 實驗過程2.0 預備知識2.0.1 多cache一致性算法——監聽法2.0.1.1 MSI協議2.0.1.2 MESI協議2.0.1.3 本題講解 2.0.2 多cache一致性算法——目錄法2.0.2.1 有中心的目錄法2.0.2…

A2B V2.0協議學習筆記(非正式版本)

一、說明 A2B全稱是 Automotive Audio Bus 汽車音頻總線,主要是解決傳統音頻總線線多、線重、成本貴等問題。 A2B V2.0總線相對V1.0主要變化點: 速率提升,高達98.304Mbps,全雙工模式 編碼方式,由之前的曼徹斯特編碼變為QPSK(正交相移鍵控)編碼,每個符合2bit數據,因此…

隨手記:多行文本域存數據有換行,回顯數據換行展示

1.在新增的時候存儲數據 <el-input type"textarea"v-model"XXXX"></el-input> 2.詳情頁返回的數據&#xff1a; replace一頓操作確實復雜 最快的方法直接寫個樣式:style"white-space: pre-line" 即可行內或者class樣式都可以 …

B2126 連續出現的字符

連續出現的字符 題目描述 給定一個字符串&#xff0c;在字符串中尋找第一個連續出現次數不低于 k k k 次的字符。 輸入格式 2 2 2 行。第 1 1 1 行是 k k k&#xff1b;第 2 2 2 行是僅包含大小寫字母的字符串。 輸出格式 字符串中第一個連續出現次數不低于 k 次的字符…

Python面試寶典:Python中與動態規劃和排序算法相關的面試筆試題(1000加面試筆試題助你輕松捕獲大廠Offer)

Python面試寶典:1000加python面試題助你輕松捕獲大廠Offer【第二部分:Python高級特性:第十二章:高級數據結構和算法:第二節:Python中實現各類高級數據結構與算法三】 第十二章:高級數據結構和算法第二節:Python中實現各類高級數據結構與算法2.3、python中與動態規劃和排…

網頁如何給js后臺傳遞數字類型參數

網頁無法通過get方法傳遞數字參數給js后臺&#xff0c;就是網頁端寫的是數字參數&#xff0c;傳遞給后臺也變成了數字字符串。而js對數字類型和字符串類型是不相同的。由于我們的代碼是通過中間件掛載接口的&#xff0c;通過joi庫檢查參數。 const Joi require(joi); //注意&…

秋招突擊——算法打卡——5/28——復習{Z字形變換、兩數之和}——新做:{整數反轉、字符串轉整數}

文章目錄 復習Z字形變換實現代碼參考代碼 兩數之和復習代碼 新作整數反轉個人實現實現代碼 參考做法字符串轉換整數個人解法 分析總結 復習 Z字形變換 實現代碼 這里使用了他的思想&#xff0c;但是沒有用他的代碼&#xff0c;雖然已經比上次簡潔了&#xff0c;但是還是不夠&…

【日記】終于鼓起勇氣買了吹風機!(356 字)

正文 好忙。今天比昨天還要忙&#xff0c;水都沒喝幾口。嗯&#xff0c;好像只喝了兩口。 今天補了一份印鑒卡&#xff0c;銷了一個戶&#xff0c;變了一個戶&#xff0c;弄了一大堆資料找人簽字&#xff0c;還順帶要解決一個押品的歷史遺留問題。 中午睡得好香&#xff0c;都不…

如何理解和使用 this 關鍵字

this 關鍵字是許多編程語言中的一個核心概念&#xff0c;在面向對象編程&#xff08;OOP&#xff09;中尤為重要。在JavaScript、Java、C、C#等語言中&#xff0c;this 扮演著至關重要的角色。理解 this 的意義和用法&#xff0c;對于編寫清晰、有效的代碼至關重要。 什么是th…

超分論文走讀

codeFormer 原始動機 高度不確定性&#xff0c;模糊到高清&#xff0c;存在一對多的映射紋理細節丟失人臉身份信息丟失 模型實現 訓練VQGAN 從而得到HQ碼本空間作為本文的離散人臉先驗。為了降低LQ-HQ映射之間的不確定性&#xff0c;我們設計盡量小的碼本空間和盡量短的Code…

ECS搭建2.8版本的redis

要在ECS&#xff08;Elastic Compute Service&#xff09;上手動搭建Redis 2.8版本&#xff0c;你可以按照以下步驟操作&#xff1a; 步驟1&#xff1a;更新系統和安裝依賴 首先&#xff0c;登錄到你的ECS實例&#xff0c;確保系統是最新的并安裝必要的依賴包&#xff1a; s…

運營推廣最容易被忽略的細節!用短鏈接推廣必須要掌握這些要點!

短鏈接是目前很多企業進行網絡推廣最常用的方式之一&#xff0c;是引流轉化的重要橋梁&#xff0c;很多工作者可能覺得用短鏈接推廣&#xff0c;只需要簡簡單單的把生成好的短鏈接放上去就行&#xff0c;但是實際上有很多細節要點是需要著重注意的&#xff0c;今天小編就圍繞這…

做外貿怎么給新老客戶定價

通常情況下我們對于新客戶的關注點要比老客戶更多一些&#xff0c;大概是因為新客戶的開發周期比較長而且不確定性也很大。 但是對于一些返單的老客戶對比來講&#xff0c;老客戶的穩定性就會相對來說增加很多&#xff0c;如果款式規格都是固定的&#xff0c;那么老客戶從選品…

[AIGC] Nginx常用變量詳解

Nginx非常強大&#xff0c;其主要功能包括HTTP服務器、反向代理、負載均衡等。Nginx的配置中有許多內置的變量&#xff0c;你可以在配置文件中使用這些變量進行靈活的配置。在本篇文章中&#xff0c;我們將介紹一些Nginx中常見的變量&#xff0c;包括proxy_add_header。 常見變…

redis顯示RDB error

報錯問題&#xff1a;"RDB error" 是指在Redis的RDB持久化過程中出現了錯誤。Redis的RDB持久化是通過將內存中的數據集快照保存到磁盤中的一種方式。如果在這個過程中遇到問題&#xff0c;Redis會記錄一條包含"RDB error"的日志信息。上圖錯誤&#xff0c;…