Mysql鎖機制相關分析

一、概述

1、鎖的定義:

鎖是協調計算機協調多個線程或線程併發訪問某一資源的機制

2、鎖的分類:

按照不同的維度劃分:

  • 從對數據操作的的類型來分,分爲,讀鎖和寫鎖。
  • 從對數據操作的粒度來分,分爲,表鎖和行鎖。

3、鎖操作:

手動增加讀表鎖:lock table 表名稱 read;

手動增加寫表鎖:lock table 表名稱write;

查看是否加鎖命令:show open tables

查看會顯示In_use,Name_locked,  當表加鎖後In_use會顯示1,表示該表加鎖了。

二、圍繞不通存儲引擎來分析鎖機制

對於開銷、加鎖速度、死鎖、粒度、併發性能,只能就具體應用的特點來說哪種鎖更合適?

基本上是圍繞三鎖機制:

表鎖(偏讀):偏向MyISAM存儲引擎,開銷小,加鎖快,無死鎖,鎖定粒度大,發生鎖衝突的概率最高,併發度最低。

行鎖(偏寫):偏向InnoDB存儲引擎,開銷大,加鎖慢,會出現死鎖,鎖定粒度小,發生鎖衝突的概率最低,併發度也最高。

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

MyISAM與InnoDB區別:

InnoDB支持事物操作,採用行級鎖,InnoDB其實也支持表級鎖,當加鎖或者索引使用不當的時候,行鎖會失效變爲表鎖。

 

1、首先來分析基於MyISAM存儲引擎的表鎖

     MyISAM的表鎖從數據操作也分讀鎖和寫鎖,下面分別來看錶鎖下的讀寫鎖情況:

(1)、讀鎖(共享鎖)

讀鎖(共享鎖):針對同一份數據,多個讀操作可以同時進行,而不會互相影響。

案例分析:

lock table user1 read(給user1增加讀鎖)

現在有兩個終端的session,分別爲session1和session2;

執行過程:

session1可以select * from user1

session1不能update user1;會出錯

session1不能查詢和修改user2,也就是session1不能修改和查詢其他的表

session2可以查詢user1 也可以查詢其他的user2等表。

session2不能修改user1,會阻塞,會一直等待,需要session1,unlock解鎖  釋放鎖,才能修改。

結論:user1加了讀鎖後,可以查看自己的表,不能更新自己,也不能修改查詢其他的表,而由於讀鎖是共享鎖,其他(session2)終端是可以讀被session1鎖住的user1的,也可以查詢其他的表,但是session2是不能修改被設置讀鎖的user1,執行更新語句會一直阻塞,處於等待的狀態,直到session1的讀鎖被釋放,纔會更新。

(2)、寫鎖(排他鎖)

寫鎖(排他鎖):當前寫操作沒有完成前,它會阻斷其他寫鎖和讀鎖。 

案例分析:

lock table user1 (給user1增加寫鎖)

現在有兩個終端的session,分別爲session1和session2;

執行過程:

session1可以select * from user1

session1可以修改更新user1

session1不可以select * from 其他表,出報錯。

session2可以查詢其他表

session2不能select * from user1 會阻塞,處於等待的狀態,必須釋放session1的寫鎖

session2更不能對user1進行其他更新操作了。

結論:

user1加寫鎖後,session1可以對自己繼續查看修改操作,但是不能對別的表進行查看和修改操作

session2不能查詢和修改user1,需要等待user1的寫鎖被釋放。

2、基於InnoDB的行鎖分析

InnoDB的表鎖從數據操作也分讀鎖和寫鎖,下面分別來看錶鎖下的讀寫鎖情況:

案例分析:

首先我們來關閉自帶的事物set autocommit=0

現在有兩個終端的session,分別爲session1和session2;   分別操作user1表(id,age)

第一種情況:

session1:update user1 set age=10 where id=1;

這時候session1查看user1表可以看到被修改的值,而session2查看user1還是原來的值,必須session1提交事物commit,session2才能查看到session1修改後的值。

第二種情況:

如果session1修改:update user1 set age=11 where id=1;這時候還沒commit提交事物,session2執行相同的更新語句update user1 set age=12 where id=1;,會一直處於等待狀態,也就是阻塞了,等session1 commit提交後,session2才能執行成功,並且session2要commit一次才能讀到修改後的值。

第三種情況:

session1執行:update user1 set age=11 where id=1;

session2執行:update user1 set age=11 where id=2;

這種情況各自處理不同行的數據,不會有影響,各自操作自己的數據。

3、無索引行行鎖升級爲表鎖

當索引使用不當時會導致行鎖變爲表鎖 

案例分析

已知user表,字段內容有id(int)和name(varchar)兩個字段,分別都建立索引。

現在有兩個終端的session,分別爲session1和session2; 

第一步:session1執行 update user set id=3 where name=4000;執行後正常,未提交事物前。

第二步:session2執行 update user set name='9002' where id=1;執行後出現阻塞。

 針對第二步爲啥會阻塞進行分析:

 按道理來說session1和session2操作的數不同行的記錄,應該互不影響呀!!!,問題在session1的update語句條件name是varchar類型,沒有加單雙引號,而索引會自動類型轉化的, 像這種情況下行鎖就變爲表鎖,性能就下降了,必須session1 commit後纔可以。

4、間隙鎖的危害

間隙鎖的定義

當我們用範圍條件而不是相等條件檢索數據,並請求共享或排他鎖時,innodb會符合條件的已有數據記錄的索引項加鎖,對於鍵值在條件範圍內但並不存在的記錄,叫間隙(GAP)。

案例分析

已知user表,字段內容有id(int)和name(varchar)兩個字段,分別有記錄id爲,1,3,4,5,6,7 但是沒有id=2的記錄。

現在有兩個終端的session,分別爲session1和session2; 

第一步session1執行 update user set name='9002' where id>1 and id<6; 未提交事物

第二步:session2想把id=2的值inster插入進來,執行插入語句會出現阻塞。

間隙鎖的危害

間隙鎖有一個致命的弱點:

當鎖定一個範圍鍵值之後,即使某些不存在的鍵值,也會被無辜的鎖定,而造成在鎖定的時候無法插入鎖定鍵值範圍的任何數據,在某些場景下這可能會對性能造成很大的危害。

三、樂觀鎖和悲觀鎖的思想

1、悲觀鎖

定義:

悲觀鎖,正如其名,它指的是對數據被外界(包括本系統當前的其他事務,以及來自外部系統的事務處理)修改持保守態度(悲觀),因此,在整個數據處理過程中,將數據處於鎖定狀態。 悲觀鎖的實現,往往依靠數據庫提供的鎖機制 (也只有數據庫層提供的鎖機制才能真正保證數據訪問的排他性,否則,即使在本系統中實現了加鎖機制,也無法保證外部系統不會修改數據)。

悲觀鎖的執行流程:

  • 在對任意記錄進行修改前,先嚐試爲該記錄加上排他鎖(exclusive locking)。
  • 如果加鎖失敗,說明該記錄正在被修改,那麼當前查詢可能要等待或者拋出異常。 具體響應方式由開發者根據實際需要決定。
  • 如果成功加鎖,那麼就可以對記錄做修改,事務完成後就會解鎖了。
  • 其間如果有其他對該記錄做修改或加排他鎖的操作,都會等待我們解鎖或直接拋出異常。

悲觀鎖優點與不足

悲觀併發控制實際上是“先取鎖再訪問”的保守策略,爲數據處理的安全提供了保證。但是在效率方面,處理加鎖的機制會讓數據庫產生額外的開銷,還有增加產生死鎖的機會;另外,在只讀型事務處理中由於不會產生衝突,也沒必要使用鎖,這樣做只能增加系統負載;還有會降低了並行性,一個事務如果鎖定了某行數據,其他事務就必須等待該事務處理完纔可以處理那行數。

2、樂觀鎖

定義

樂觀鎖( Optimistic Locking ) 相對悲觀鎖而言,樂觀鎖假設認爲數據一般情況下不會造成衝突,所以在數據進行提交更新的時候,纔會正式對數據的衝突與否進行檢測,如果發現衝突了,則讓返回用戶錯誤的信息,讓用戶決定如何去做。

樂觀鎖的執行流程

相對於悲觀鎖,在對數據庫進行處理的時候,樂觀鎖並不會使用數據庫提供的鎖機制。一般的實現樂觀鎖的方式就是記錄數據版本。

數據版本,爲數據增加的一個版本標識。當讀取數據時,將版本標識的值一同讀出,數據每更新一次,同時對版本標識進行更新。當我們提交更新的時候,判斷數據庫表對應記錄的當前版本信息與第一次取出來的版本標識進行比對,如果數據庫表當前版本號與第一次取出來的版本標識值相等,則予以更新,否則認爲是過期數據。

實現數據版本有兩種方式,第一種是使用版本號,第二種是使用時間戳

樂觀鎖優點與不足

樂觀併發控制相信事務之間的數據競爭(data race)的概率是比較小的,因此儘可能直接做下去,直到提交的時候纔去鎖定,所以不會產生任何鎖和死鎖。但如果直接簡單這麼做,還是有可能會遇到不可預期的結果,例如兩個事務都讀取了數據庫的某一行,經過修改以後寫回數據庫,這時就遇到了問題。

https://www.bilibili.com/video/BV1KW411u7vy?p=61

https://blog.csdn.net/qq_37933685/article/details/80717515?ops_request_misc=&request_id=&biz_id=102&utm_term=mysql%E9%94%81%E6%9C%BA%E5%88%B6&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-2-80717515

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