【MySQL】MySQL有幾種鎖

目錄

一、按照對數據操作的鎖粒度來分:行級鎖、表級鎖、頁級鎖、間隙鎖

1 行級鎖

2 表級鎖

3 頁級鎖

二、按照鎖的共享策略來分:共享鎖、排他鎖、意向共享鎖、意向排他鎖

innodb的意向鎖有什麼作用?

三、從加鎖策略上分:樂觀鎖和悲觀鎖

四、其他:自增鎖

自增鎖(AUTO-INC鎖)

外鍵檢測的加鎖策略


一、按照對數據操作的鎖粒度來分:行級鎖表級鎖頁級鎖、間隙鎖

MyISAM和MEMORY採用表級鎖(table-level locking)

BDB採用頁面鎖(page-level locking)或表級鎖,默認爲頁面鎖

InnoDB支持行級鎖(row-level locking)和表級鎖,默認爲行級鎖

 

1 行級鎖

(1) 描述

行級鎖是mysql中鎖定粒度最細的一種鎖。表示只針對當前操作的行進行加鎖。行級鎖能大大減少數據庫操作的衝突,其加鎖粒度最小,但加鎖的開銷也最大。行級鎖分爲共享鎖和排他鎖

(2) 特點

開銷大,加鎖慢,會出現死鎖。發生鎖衝突的概率最低,併發度也最高。

 

其實行級鎖和頁級鎖之間還有其他鎖粒度的鎖,就是間隙鎖臨鍵鎖

InnoDB有三種行鎖的算法:

1,Record Lock(記錄鎖):單個行記錄上的鎖。這個也是我們日常認爲的行鎖。

2,Gap Lock(間隙鎖):間隙鎖,鎖定一個範圍,但不包括記錄本身(只不過它的鎖粒度比記錄鎖的鎖整行更大一些,他是鎖住了某個範圍內的多個行,包括根本不存在的數據)。GAP鎖的目的,是爲了防止同一事務的兩次當前讀,出現幻讀的情況。該鎖只會在隔離級別是RR或者以上的級別內存在。間隙鎖的目的是爲了讓其他事務無法在間隙中新增數據。

3,Next-Key Lock(臨鍵鎖)它是記錄鎖和間隙鎖的結合,鎖定一個範圍,並且鎖定記錄本身。對於行的查詢,都是採用該方法,主要目的是解決幻讀的問題。next-key鎖是InnoDB默認的鎖

上面這三種鎖都是排它鎖(X鎖)

 

next-key lock的效果相當於一個記錄鎖加一個間隙鎖。當next-key lock加在某索引上,則該記錄和它前面的區間都被鎖定。

假設有記錄1, 3, 5, 7,現在記錄5上加next-key lock,則會鎖定區間(3, 5],任何試圖插入到這個區間的記錄都會阻塞。

 

注意,由於其效果相當於(3, 5)上的gap lock加5上的record lock,而且gap lock是可重入的相互不阻塞的(上文講過),當其它事務試圖獲取(3, 5)的gap lock時,不會被阻塞;但如果要獲取5上的record lock,就會阻塞;如果要獲取5上的next-key lock,同樣會阻塞。

 

record lock、gap lock、next-key lock,都是加在索引上的。假設有記錄1,3,5,7,則5上的記錄鎖會鎖住5,5上的gap lock會鎖住(3,5),5上的next-key lock會鎖住(3,5]。

 

注意,next-Key鎖規定是左開右閉區間

以這個圖爲例,插入id=10,它加的next-key其實就是一個左開右閉,id=6本身沒有加鎖,所以是開區間,id=10本身加鎖了,所以是閉區間。即(6,10]

 

2 表級鎖

(1) 描述

表級鎖是mysql中鎖定粒度最大的一種鎖,表示對當前操作的整張表加鎖,它實現簡單,資源消耗較少,被大部分mysql引擎支持。最常使用的MyISAM與InnoDB都支持表級鎖定。表級鎖定分爲表共享讀鎖(共享鎖)與表獨佔寫鎖(排他鎖)

(2) 特點

開銷小,加鎖快,不會出現死鎖。發生鎖衝突的概率最高,併發度也最低。

  • LOCK TABLE my_table_name READ;  用讀鎖鎖表,會阻塞其他事務修改表數據。
  • LOCK TABLE my_table_name WRITE; 用寫鎖鎖表,會阻塞其他事務讀和寫。

MyISAM在執行查詢語句(SELECT)前,會自動給涉及的所有表加讀鎖,在執行更新操作(UPDATE、DELETE、INSERT等)前,會自動給涉及的表加寫鎖,這個過程並不需要用戶干預,因此,用戶一般不需要直接用LOCK TABLE命令給MyISAM表顯式加鎖。

但是在InnoDB中如果需要表鎖就需要顯式地聲明瞭。

 

3 頁級鎖

(1) 描述

頁級鎖是 MySQL 中鎖定粒度介於行級鎖和表級鎖中間的一種鎖。表級鎖速度快,但衝突多,行級衝突少,但速度慢。因此,採取了折中的頁級鎖,一次鎖定相鄰的一組記錄。BDB 支持頁級鎖。

(2) 特點

開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,併發度一般。

 

二、按照鎖的共享策略來分:共享鎖、排他鎖、意向共享鎖、意向排他鎖

共享鎖和排他鎖在MySQL中具體的實現就是讀鎖和寫鎖:

  • 讀鎖(共享鎖):Shared Locks(S鎖),針對同一份數據,多個讀操作可以同時進行而不會互相影響
  • 寫鎖(排它鎖):Exclusive Locks(X鎖),當前寫操作沒有完成前,它會阻斷其他寫鎖和讀鎖
  • IS鎖:意向共享鎖、Intention Shared Lock。當事務準備在某條記錄上加S鎖時,需要先在表級別加一個IS鎖。
  • IX鎖:意向排他鎖、Intention Exclusive Lock。當事務準備在某條記錄上加X鎖時,需要先在表級別加一個IX鎖。

IS、IX鎖是表級鎖,它們的提出僅僅爲了在之後加表級別的S鎖和X鎖時可以快速判斷表中的記錄是否被上鎖,以避免用遍歷的方式來查看錶中有沒有上鎖的記錄。就是說當對一個行加鎖之後,如果有打算給行所在的表加一個表鎖,必須先看看該表的行有沒有被加鎖,否則就會出現衝突。IS鎖和IX鎖就避免了判斷表中行有沒有加鎖時對每一行的遍歷。直接查看錶有沒有意向鎖就可以知道表中有沒有行鎖。

注意:如果一個表中有多個行鎖,他們都會給表加上意向鎖,意向鎖和意向鎖之間是不會衝突的。

 

innodb的意向鎖有什麼作用?

mysql官網上對於意向鎖的解釋中有這麼一句話

“The main purpose of IX and IS locks is to show that someone is locking a row, or going to lock a row in the table.”

意思是說加意向鎖的目的是爲了表明某個事務正在鎖定一行或者將要鎖定一行。

那麼,意向鎖的作用就是“表明”加鎖的意圖,可是爲什麼要表明這個 意圖呢?

如果僅僅鎖定一行僅僅需要加一個鎖,那麼就直接加鎖就好了,這裏要表明加鎖意圖的原因是因爲要鎖定一行不僅僅是要加一個鎖,而是要做一系列操作嗎?

 

我最近也在看這個,我說一下我的理解

①在mysql中有表鎖,LOCK TABLE my_tabl_name READ;  用讀鎖鎖表,會阻塞其他事務修改表數據。LOCK TABLE my_table_name WRITe; 用寫鎖鎖表,會阻塞其他事務讀和寫。

②Innodb引擎又支持行鎖,行鎖分爲共享鎖,一個事務對一行的共享只讀鎖。排它鎖,一個事務對一行的排他讀寫鎖。

③這兩中類型的鎖共存的問題考慮這個例子:

事務A鎖住了表中的一行,讓這一行只能讀,不能寫。之後,事務B申請整個表的寫鎖。如果事務B申請成功,那麼理論上它就能修改表中的任意一行,這與A持有的行鎖是衝突的。

數據庫需要避免這種衝突,就是說要讓B的申請被阻塞,直到A釋放了行鎖。

 

數據庫要怎麼判斷這個衝突呢?

step1:判斷表是否已被其他事務用表鎖鎖表

step2:判斷表中的每一行是否已被行鎖鎖住

注意step2,這樣的判斷方法效率實在不高,因爲需要遍歷整個表。

於是就有了意向鎖。在意向鎖存在的情況下,事務A必須先申請表的意向共享鎖,成功後再申請一行的行鎖。在意向鎖存在的情況下,

上面的判斷可以改成

step1:不變

step2:發現表上有意向共享鎖,說明表中有些行被共享行鎖鎖住了,因此,事務B申請表的寫鎖會被阻塞。

 

注意:申請意向鎖的動作是數據庫完成的,就是說,事務A申請一行的行鎖的時候,數據庫會自動先開始申請表的意向鎖,不需要我們程序員使用代碼來申請。

 

總結:爲了實現多粒度鎖機制(白話:爲了表鎖和行鎖都能用)

 

當然,這四種鎖都屬於悲觀鎖

意向鎖之間都不會發生衝突,排他鎖跟誰都衝突

 

 

三、從加鎖策略上分:樂觀鎖和悲觀鎖

悲觀鎖認爲對於同一個數據的併發操作,一定是會發生修改的(或者增刪改多,查少),哪怕沒有修改,也會認爲修改。因此對於同一個數據的併發操作,悲觀鎖採取加鎖的形式。悲觀的認爲,不加鎖的併發操作一定會出問題

樂觀鎖則認爲對於同一個數據的併發操作,是不會發生修改的(或者增刪改少,查多)。在更新數據的時候,會採用不斷嘗試更新的方式來修改數據。也就是先不管資源有沒有被別的線程佔用,直接取申請操作,如果沒有產生衝突,那就操作成功,如果產生衝突,有其他線程已經在使用了,那麼就不斷地輪詢。樂觀的認爲,不加鎖的併發操作是沒有事情的。就是通過記錄一個數據歷史記錄的多個版本,如果修改完之後發現有衝突再將版本返回到沒修改的樣子,樂觀鎖就是不加鎖。好處就是減少上下文切換,壞處是浪費CPU時間。

 

四、其他:自增鎖

自增鎖(AUTO-INC鎖)

自增鎖是一種特殊的表級鎖,主要用於事務中插入自增字段,也就是我們最常用的自增主鍵id。通過innodb_autoinc_lock_mode參數可以設置自增主鍵的生成策略。防止併發插入數據的時候自增id出現異常

當一張表的某個字段是自增列時,innodb會在該索引的末位加一個排它鎖。爲了訪問這個自增的數值,需要加一個表級鎖,不過這個表級鎖的持續時間只有當前sql,而不是整個事務,即當前sql執行完,該表級鎖就釋放了。其他session無法在這個表級鎖持有時插入任何記錄。


相關文章:【MySQL】MySQL的鎖與事務隔離級別詳解
                  【MySQL】InnoDB行格式、數據頁結構以及索引底層原理分析

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章