深入理解mysql系列_深入理解MySQL系列之锁
按鎖思想分類
悲觀鎖
優點:適合在寫多讀少的并發環境中使用,雖然無法維持非常高的性能,但是在樂觀鎖無法提更好的性能前提下,可以做到數據的安全性
缺點:加鎖會增加系統開銷,雖然能保證數據的安全,但數據處理吞吐量低,不適合在讀書寫少的場合下使用
樂觀鎖
優點:在讀多寫少的并發場景下,可以避免數據庫加鎖的開銷,提高DAO層的響應性能,很多情況下ORM工具都有帶有樂觀鎖的實現,所以這些方法不一定需要我們人為的去實現。
缺點:在寫多讀少的并發場景下,即在寫操作競爭激烈的情況下,會導致CAS多次重試,沖突頻率過高,導致開銷比悲觀鎖更高。
實現:數據庫層面的樂觀鎖其實跟CAS思想類似, 通數據版本號或者時間戳也可以實現。
按鎖粒度分類
表鎖
表鎖是指對一整張表加鎖,一般是 DDL 處理時使用
表鎖由 MySQL Server 實現,表級鎖更適合于以查詢為主,并發用戶少,只有少量按索引條件更新數據的應用,如Web 應用
優點:開銷小,加鎖快;不會出現死鎖;
缺點:鎖定粒度大,發生鎖沖突的概率最高,并發度最低。
頁鎖:介于表鎖和行鎖之間。BDB 存儲引擎采用的是頁面鎖(page-level locking)
行鎖
行鎖則是鎖定某一行或者某幾行,或者行與行之間的間隙。
行鎖則是存儲引擎實現,行級鎖更適合于有大量按索引條件并發更新少量不同數據,同時又有并發查詢的應用,如一些在線事務處理(OLTP)系統
優點:鎖定粒度最小,發生鎖沖突的概率最低,并發度也最高。
缺點:開銷大,加鎖慢;會出現死鎖;
InnoDB行鎖類型
標準
共享鎖(S):允許一個事務去讀一行,阻止其他事務獲得相同數據集的排他鎖
排他鎖(X):允許獲得排他鎖的事務更新數據,阻止其他事務取得相同數據集的共享讀鎖和排他寫鎖。
數據庫并發場景主要有三種:
讀-讀:不存在任何問題,也不需要并發控制
讀-寫:有隔離性問題,可能遇到臟讀,幻讀,不可重復讀
寫-寫:可能存更新丟失問題,比如第一類更新丟失,第二類更新丟失
更細粒度
共享鎖(S)
排他鎖(X)
意向共享鎖(IS):事務打算給數據行加行共享鎖,事務在給一個數據行加共享鎖前必須先取得該表的 IS 鎖。
意向排他鎖(IX):事務打算給數據行加行排他鎖,事務在給一個數據行加排他鎖前必須先取得該表的 IX 鎖。
一致性(非)鎖定讀
一致性非鎖定讀:
一致性非鎖定讀由MVCC(多版本并發控制)實現。MVCC其實就是在每一行記錄后面增加兩個隱藏列,記錄創建版本號和刪除版本號,而每一個事務在啟動的時候,都有一個唯一的遞增的版本號
詳細可參考前文《深入理解MySQL系列之redo log、undo log和binlog》
一致性鎖定讀:
SELECT ... FOR UPDATE //加X鎖
SELECT ... LOCK IN SHARE MODE //加S鎖
鎖的算法
行鎖的三種算法:
Record Lock:當個行記錄上的鎖
Gap Lock:間隙鎖,鎖定一個范圍,但不包含記錄本身
Next Key Lock:Gap Lock + Record Lock ,鎖定一個范圍,并且鎖定記錄本身(只有REPEATABLE READ隔離級別有)
在默認事務隔離級別(REPEATABLE READ)下,InnoDB采用Next Key Lock解決幻讀(Phantom Problem)。對一個范圍加X鎖,從而這個范圍不允許插入,所以避免了幻讀。
此外,還可以用Next key lock實現唯一性檢查。如下,用戶通過索引查詢一個值,并對該行加一個S Lock;如果行不存在,鎖定一個范圍,新插入值也是唯一的。
SELECT * FROM TABLE WHERE COL = xxx LOCK IN SHARE MODE;
// 如果沒有找到任何行
INSERT INTO TABLE VALUES(...)
間隙鎖加鎖原則:
1、加鎖的基本單位是 NextKeyLock,是前開后閉區間。
2、查找過程中訪問到的對象才會加鎖。
3、索引上的等值查詢,給唯一索引加鎖的時候,NextKeyLock退化為行鎖。
4、索引上的等值查詢,向右遍歷時且最后一個值不滿足等值條件的時候,NextKeyLock退化為間隙鎖。
5、唯一索引上的范圍查詢會訪問到不滿足條件的第一個值為止。
自增鎖
AUTOINC 鎖又叫自增鎖(一般簡寫成 AI 鎖),是一種表鎖,當表中有自增列(AUTOINCREMENT)時出現。
當插入表中有自增列時,數據庫需要自動生成自增值,它會先為該表加 AUTOINC 表鎖,阻塞其他事務的插入操作,這樣保證生成的自增值肯定是唯一的。AUTOINC 鎖具有如下特點:
AUTO_INC 鎖互不兼容,也就是說同一張表同時只允許有一個自增鎖;
自增值一旦分配了就會 +1,如果事務回滾,自增值也不會減回去,所以自增值可能會出現中斷的情況。
顯然,AUTOINC 表鎖會導致并發插入的效率降低,為了提高插入的并發性,MySQL 從 5.1.22 版本開始,引入了一種可選的輕量級鎖(mutex)機制來代替 AUTOINC 鎖,可以通過參數 innodbautoinclockmode 來靈活控制分配自增值時的并發策略。具體可以參考 MySQL 的 AUTOINCREMENT Handling in InnoDB 一文
死鎖
概念:死鎖是指兩個或兩個以上的事務執行過程中,因爭奪資源而造成的一種互相等待的現象。
解決死鎖第一種方法:超時,然后對事務回滾
缺點:若超時的事務所占權重比較大,如事務更新了很多行,占用了較多的undo log,這時采用FIFO方式就不合適了,因為回滾這個事務的時間相對另一個事務所占用的時間可能會多很多。
wait-for graph等待圖方式進行死鎖檢測
InnoDB采用的方式。
wait-for graph要求數據庫保存兩種信息,通過下面兩個鏈表構造出一張圖,如果這個圖中存在回路,就代表存在死鎖,因此資源間發生相互等待。
鎖的信息鏈表
事務等待鏈表
如下圖示例,事務等待鏈表有4個事務,而右邊鎖信息鏈表中,row1中事務t1要等待事務t2資源,所以在下wait-for graph圖中就有一條t1指向t2的箭頭;而row2中tt2、t3需要等待t1中占用row2資源,故t2、t3各有個箭頭指向t1(t1、t4兩個S鎖兼容)。依次最后得到下面的圖。
可以發現(t1, t2)存在回路,因此存在死鎖。
所以wait-for graph是一種主動的死鎖檢查機制,若存在死鎖,選擇回滾undo量最小的事務。(wait-for graph采用圖的深度優先算法)
總結
以上是生活随笔為你收集整理的深入理解mysql系列_深入理解MySQL系列之锁的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java学习路线图(完整详细2021版)
- 下一篇: linux 离线安装mysql_Linu