對於大部分的後端開發來講,數據庫尤爲是MySQL是一個離不開的知識點,那麼今天就分享一下最近學習的數據庫中的鎖相關知識,並以此解釋事務隔離性問題。
以下是整理的Mysql中鎖的相關知識點 java
鎖是數據庫系統區別於文件系統的一個關鍵性區別。鎖機制用於管理數據庫共享資源的併發訪問。也是實現事務的關鍵。算法
在MySQL中根據鎖的粒度分爲全局鎖,表鎖和行鎖,鎖的粒度從大到小。sql
全局鎖:鎖住的是數據庫實例,被鎖住時只讀不可寫。須要顯示的調用鎖庫語句:Flush table with lock。 使用場景通常是全庫備份。數據庫
表鎖 :分爲表鎖和元數據鎖(MDL)後端
表鎖相似全局鎖,只是鎖住對象時表,分讀鎖和寫鎖。
元數據鎖(MDL),不須要顯示的調用,當對一個表進行增刪改查時會加MDL讀鎖 ,當對錶結構進行修改時(如加減字段)那麼此時會對錶加上寫鎖。這裏的讀鎖之間是不會互相排斥的,可是寫鎖是互斥的緩存
行鎖:對錶中的具體記錄進行加鎖,是項目中最多見的一種鎖。行鎖是對索引加鎖。以前說過,每一張表都是有索引的,若是有主鍵,主鍵會鍵索引,若是沒有主鍵,Innodb會爲每行記錄加一個默認列row_index 在這個列上面會創建索引。併發
InnoDB實現了以下兩種標準的行級鎖:學習
以下圖顯示了共享鎖和排他鎖的兼容性 spa
在對鎖有了簡單的瞭解後,下面就來講說鎖的算法。
3d
你們可能對前面兩個比較好理解,對於第三個Next Key Lock會略感陌生,那麼下面就是對該算法的解釋。
假設表上面id列有索引4,5,7,10)這四個值,那麼加鎖的狀況就是(-無窮大,4],(4,5],(5,7],(7,10],(10,+無窮大),若是id不是聚簇索引或者惟一索引,那麼執行select * from t where id=5 for update ,加鎖的狀況就是 (4,5)和(5,7)那麼 insert into t select 6 ;會被鎖住沒法插入,可是insert into t select 8,或者insert into t select 2都是能夠插入。
在可重複讀的隔離級別下默認使用的是Next Key Lock,經過這個鎖算法能夠解決幻讀問題。使用讀提交的隔離級別會關閉Gap Lock和Next Key Lock。
正是由於有了鎖咱們能夠對共享資源進行併發控制,但帶來便利的同時,也帶來了其餘問題。
在繼續往下講以前,咱們須要瞭解什麼是鎖的兩階段協議
1 . 鎖在須要的時候纔會加上去;
2. 事務結束纔會釋放鎖。
怎麼理解呢?
通俗的講就是,事務開啓時不會立馬加鎖,只有在執行須要加鎖的sql時纔會加上鎖好比insert ,delete等;可是鎖的釋放是等事務提交時纔會釋放,而不是執行完sql就釋放鎖。也正是因爲這個緣由纔出現了阻塞和死鎖的現象。
因爲不一樣鎖之間的兼容問題,在有些時刻,一個事務中的鎖須要等待另外一個事務中的鎖的釋放它鎖佔用的資源,這個就是阻塞。
在Innodb中,有一個參數innodb_lock_wait_timeout 是用來控制等待時間的,默認是50秒,當一個事務等待超時時會出現1205異常,在默認狀況下Innodb不會回滾超時引起的錯誤異常(在Innodb中大部分異常不會有回滾操做除了死鎖檢測)。若是想回滾能夠業務本身手動調用,或者將參數innodb_rollback_on_timeout設置爲on,默認是off。
和java中死鎖的概念差很少,具體是指:兩個或者兩個以上的事務在執行過程當中,由於爭奪鎖資源而形成的一種互相等待的現象。
在上面有提到兩階段的協議,也正是其中提到的事務提交時纔會釋放鎖,那麼就會在事務結束時出現AB和BA的互相等待鎖的狀況。這個就是致使死鎖的緣由。
對於死鎖問題的解決通常有三種方向
解釋一下什麼死鎖檢測:
爲了可以主動進行死鎖檢測,數據庫中保存了2種信息 「鎖的鏈表信息」和「事務等待鏈表」,經過這兩個鏈表能夠構造出一張以事務爲節點的圖(wait-for graph),圖中事務節點能夠互相指向,當T1等待T2鎖佔用的資源時,會有一個T1指向T2的定義,當事務請求鎖時就會檢測這張圖,若是出現循環指向,那麼就會報1213異常,這時會將undo log量最少的事務進行回滾。
死鎖的檢測會致使機器的cpu利用率高,尤爲是在併發度較高時,所以能夠經過innodb_deadlock_detect開關來關閉死鎖檢測。
複製代碼
今天主要分析了MySQL中的鎖的相關知識,只有認識了鎖那麼在解決數據庫方面的問題時纔會更加駕輕就熟。你們若是有問題能夠一塊兒討論。
未完待續!!!!