全局鎖是什么?全局鎖有什么用?全局鎖怎么用?
全局鎖主要用在邏輯備份過程中,對于InnoDB 引擎的庫,使用–single-transaction
;
MySQL 提供了一個加全局讀鎖的方法,命令是 Flush tables with read lock (FTWRL),讓整個庫處于只讀狀態。
表鎖是什么?表鎖有什么用?表鎖怎么用?
表鎖一般是在數據庫引擎不支持行鎖的時候才會被用到的.
表鎖的語法是 lock tables … read/write;
加上讀鎖,不會限制別的線程讀,但會限制別的線程寫。加上寫鎖,會限制別的線程讀寫。
行鎖是什么?行鎖有什么用?行鎖怎么用?
行鎖就是針對數據表中行記錄的鎖。
比如事務 A 更新了一行,而這時候事務 B 也要更新同一行,則必須等事務 A 的操作完成后才能進行更新。
在 InnoDB 事務中,行鎖是在需要的時候才加上的,但并不是不需要了就立刻釋放,而是要等到事務結束時才釋放。這個就是兩階段鎖協議。
事務 B 的 update 語句會被阻塞,直到事務 A 執行 commit 之后,事務 B 才能繼續執行。
一定知道了事務 A 持有的兩個記錄的行鎖,都是在 commit 的時候才釋放的。若行鎖不是在 commit 之后被釋放,而是在該語句執行完就被釋放,則不會出現事務 B 被鎖住。
如果你的事務中需要鎖多個行,要把最可能造成鎖沖突、最可能影響并發度的鎖盡量往后放。
調整語句順序并不能完全避免死鎖。
死鎖與死鎖檢測
并發系統中不同線程出現循環資源依賴,涉及的線程都在等待別的線程釋放資源時,就會導致這幾個線程都進入無限等待的狀態,稱為死鎖。
為了避免這個操作,常用死鎖檢測。
發起死鎖檢測,發現死鎖后,主動回滾死鎖鏈條中的某一個事務,讓其他事務得以繼續執行。將參innodb_deadlock_detect
設置為 on
,表示開啟這個邏輯。
死鎖檢測算法復雜度很高 N個進程,遍歷N遍,M個資源,每個資源操作一次。則復雜度 O(M*N^2)。
假設有 1000 個并發線程要同時更新同一行,那么死鎖檢測操作就是 100 萬這個量級的。最終檢測的結果可能是沒有死鎖,但是這期間要消耗大量的 CPU 資源。
何時會死鎖檢測
每條事務執行前都會進行檢測嗎?
并不是,如果他要加鎖訪問的行上有鎖,他才要檢測。
一致性讀不會加鎖,就不需要做死鎖檢測;
并不是每次死鎖檢測都都要掃所有事務。比如某個時刻,事務等待狀態是這樣的:
B在等A,
D在等C,
現在來了一個E,發現E需要等D,那么E就判斷跟D、C是否會形成死鎖,這個檢測不用管B和A。
死鎖檢測其實就是算法,環的檢測,不必每次遍歷一遍當前事務,只需要判斷事務鏈表中,每加入一個新事物后是否有環的生成,有就形成死鎖。這個方法和leetcode的鏈表中的環檢測應該是一個道理。
如何避免高量級的死鎖檢測
為了避免這個問題,一般來說有兩種方法:
1、果你能確保這個業務一定不會出現死鎖,可以臨時把死鎖檢測關掉。一旦發生死鎖現象,則會出現超時(50s)
2、控制并發度:
1、對于相同行的更新,在進入引擎之前排隊。
2、減少行更新鎖沖突的方法:將單行拆成邏輯上的多行
練習
如果你要刪除一個表里面的前 10000 行數據,有以下三種方法可以做到:
第一種,直接執行 delete from T limit 10000;
第二種,在一個連接中循環執行 20 次 delete from T limit 500;
第三種,在 20 個連接中同時執行 delete from T limit 500。
方案一,事務相對較長,則占用鎖的時間較長,會導致其他客戶端等待資源時間較長。
方案二,串行化執行,將相對長的事務分成多次相對短的事務,則每次事務占用鎖的時間相對較短,其他客戶端在等待相應資源的時間也較短。這樣的操作,同時也意味著將資源分片使用(每次執行使用不同片段的資源),可以提高并發性。
方案三,人為自己制造鎖競爭,加劇并發量。