天天看點

mysql資料庫的各種鎖_資料庫基礎(三)Mysql裡的各種鎖

在了解mysql中的各種鎖之前你還需要了解這些

一、加鎖的目的是什麼?

在我們了解資料庫鎖之前,首先我們必須要明白加鎖的目的是為了解決什麼問題,如果你還不清楚的話,那麼從現在起你應該知道,資料庫的鎖是為了解決事務的隔離性問題,為了讓事務之間互相不影響,每個事務進行操作的時候都會對資料加上一把特有的鎖,防止其他事務同時操作資料。如果你想一個人靜一靜,不被别人打擾,那麼請在你的房門上加上一把鎖。

二、鎖實是基于什麼實作的?

為了後面大家後面對鎖了解的更透徹,是以務必要對此進行說明,鎖是基于什麼實作的,你現實生活中家裡的鎖是基于門來實作的,那麼資料庫的鎖又是基于什麼實作的呢? 那麼我在這裡可以告訴你,資料庫裡面的鎖是基于索引實作的,在Innodb中我們的鎖都是作用在索引上面的,當我們的SQL命中索引時,那麼鎖住的就是命中條件内的索引節點(行鎖),如果沒有命中索引的話,那我們鎖的就是整個索引樹(表鎖),如下圖一下鎖住的是整棵樹還是某幾個節點,完全取決于你的條件是否有命中到對應的索引節點。

innodb索引結構圖(B+ tree):

三、鎖的分類。

資料庫裡有的鎖有很多種,為了方面了解,是以我根據其相關性"人為"的對鎖進行了一個分類,分别如下

基于鎖的屬性分類:共享鎖、排他鎖。

基于鎖的粒度分類:表鎖、行鎖、記錄鎖、間隙鎖、臨鍵鎖。

基于鎖的狀态分類:意向共享鎖、意向排它鎖。

1、屬性鎖

共享鎖(Share Lock)

共享鎖又稱讀鎖,簡稱S鎖;當一個事務為資料加上讀鎖之後,其他事務隻能對該資料加讀鎖,而不能對資料加寫鎖,直到所有的讀鎖釋放之後其他事務才能對其進行加持寫鎖。

共享鎖的特性主要是為了支援并發的讀取資料,讀取資料的時候不支援修改,避免出現重複讀的問題。

排他鎖(eXclusive Lock)

排他鎖又稱寫鎖,簡稱X鎖;當一個事務為資料加上寫鎖時,其他請求将不能再為資料加任何鎖,直到該鎖釋放之後,其他事務才能對資料進行加鎖。

排他鎖的目的是在資料修改時候,不允許其他人同時修改,也不允許其他人讀取。避免了出現髒資料和髒讀的問題。

2、粒度鎖

表鎖

表鎖是指上鎖的時候鎖住的是整個表,當下一個事務通路該表的時候,必須等前一個事務釋放了鎖才能進行對表進行通路;

特點: 粒度大,加鎖簡單,容易沖突;

行鎖

行鎖是指上鎖的時候鎖住的是表的某一行或多行記錄,其他事務通路同一張表時,隻有被鎖住的記錄不能通路,其他的記錄可正常通路;

特點:粒度小,加鎖比表鎖麻煩,不容易沖突,相比表鎖支援的并發要高;

記錄鎖(Record Lock)

記錄鎖也屬于行鎖中的一種,隻不過記錄鎖的範圍隻是表中的某一條記錄,記錄鎖是說事務在加鎖後鎖住的隻是表的某一條記錄。

觸發條件:精準條件命中,并且命中的條件字段是唯一索引;

例如:update user_info set name=’張三’ where id=1 ,這裡的id是唯一索引。

記錄鎖的作用:加了記錄鎖之後資料可以避免資料在查詢的時候被修改的重複讀問題,也避免了在修改的事務未送出前被其他事務讀取的髒讀問題。

間隙鎖(Gap Lock)

間隙鎖屬于行鎖中的一種,間隙鎖是在事務加鎖後其鎖住的是表記錄的某一個區間,當表的相鄰ID之間出現空隙則會形成一個區間,遵循左開右閉原則。

比如下面的表裡面的資料ID 為 1,4,5,7,10 ,那麼會形成以下幾個間隙區間,-n-1區間,1-4區間,7-10區間,10-n區間 (-n代表負無窮大,n代表正無窮大)

觸發條件:範圍查詢并且查詢未命中記錄,查詢條件必須命中索引、間隙鎖隻會出現在REPEATABLE_READ(重複讀)的事務級别中。

例如:對應上圖的表執行select * from user_info where id>1 and id<4(這裡的id是唯一索引) ,這個SQL查詢不到對應的記錄,那麼此時會使用間隙鎖。

間隙鎖作用:防止幻讀問題,事務并發的時候,如果沒有間隙鎖,就會發生如下圖的問題,在同一個事務裡,A事務的兩次查詢出的結果會不一樣。

臨鍵鎖(Next-Key Lock)

臨鍵鎖也屬于行鎖的一種,并且它是INNODB的行鎖預設算法,總結來說它就是記錄鎖和間隙鎖的組合,臨鍵鎖會把查詢出來的記錄鎖住,同時也會把該範圍查詢内的所有間隙空間也會鎖住,再之它會把相鄰的下一個區間也會鎖住。

例如:下面表的資料執行 select * from user_info where id>1 and id<=13 for update ;

會鎖住ID為 1,5,10的記錄;同時會鎖住,1至5,5至10,10至15的區間。

觸發條件:範圍查詢并命中,查詢命中了索引。

臨鍵鎖的作用:結合記錄鎖和間隙鎖的特性,臨鍵鎖避免了在範圍查詢時出現髒讀、重複讀、幻讀問題。加了臨鍵鎖之後,在範圍區間内資料不允許被修改和插入。

3、狀态鎖

狀态鎖包括意向共享鎖和意向排它鎖,把他們區分為狀态鎖的一個核心邏輯,是因為這兩個鎖都是都是描述是否可以對某一個表進行加表鎖的狀态。

意向鎖的解釋:當一個事務試圖對整個表進行加鎖(共享鎖或排它鎖)之前,首先需要獲得對應類型的意向鎖(意向共享鎖或意向共享鎖)

意向共享鎖

當一個事務試圖對整個表進行加共享鎖之前,首先需要獲得這個表的意向共享鎖。

意向排他鎖

當一個事務試圖對整個表進行加排它鎖之前,首先需要獲得這個表的意向排它鎖。

為什麼我們需要意向鎖?

意向鎖光從概念上可能有點難了解,是以我們有必要從一個案例來分析其作用,這裡首先我們先要有一個概念那就是innodb加鎖的方式是基于索引,并且加鎖粒度是行鎖,然後我們來看下面的案例。

第一步:

事務A對user_info表執行一個SQL:update user_info set name =”張三” where id=6 加鎖情況如下圖;

第二步:

與此同時資料庫又接收到事務B修改資料的請求:SQL: update user_info set name =”李四”;

1、因為事務B是對整個表進行修改操作,那麼此SQL是需要對整個表進行加排它鎖的(update加鎖類型為排他鎖);

2、我們首先做的第一件事是先檢查這個表有沒有被别的事務鎖住,隻要有事務對表裡的任何一行資料加了共享鎖或排他鎖我們就無法對整個表加鎖(排他鎖不能與任何屬性的鎖相容)。

3、因為INNODB鎖的機制是基于行鎖,那麼這個時候我們會對整個索引每個節點一個個檢查,我們需要檢查每個節點是否被别的事務加了共享鎖或排它鎖。

4、最後檢查到索引ID為6的節點被事務A鎖住了,最後導緻事務B隻能等待事務A鎖的釋放才能進行加鎖操作。

思考:

在A事務的操作過程中,後面的每個需要對user_info加持表鎖的事務都需要周遊整個索引樹才能知道自己是否能夠進行加鎖,這種方式是不是太浪費時間和損耗資料庫性能了?

是以就有了意向鎖的概念:如果當事務A加鎖成功之後就設定一個狀态告訴後面的人,已經有人對表裡的行加了一個排他鎖了,你們不能對整個表加共享鎖或排它鎖了,那麼後面需要對整個表加鎖的人隻需要擷取這個狀态就知道自己是不是可以對表加鎖,避免了對整個索引樹的每個節點掃描是否加鎖,而這個狀态就是我們的意向鎖。