mysql的鎖
MySQL的鎖mysql
- 全局鎖:對數據庫實例加鎖
- MySQL提供了一個加全局讀鎖的方法:Flush tables with read lock(FTWRL)
- 使用場景:作全庫邏輯備份。
- 官方自帶的邏輯備份工具mysqldump,使用時帶上參數-single-transaction,導數據以前就會啓動一個事務,來確保拿到一致性視圖。因爲MVCC的支持,這個過程是能夠正常更新的。
- FTWRL用在MyISAM這種不支持事務的引擎上。
- single-transaction方法只能用在全部的表都使用事務引擎的庫。
- set global readonly=true也可讓全庫進入只讀狀態,可是不推薦用在全庫備份的場景下。
- 表級鎖
- 分類
- 表鎖
- 語法
- 加鎖:lock tables ... read/write
- 釋放鎖:unlock tables
- 使用場景:非事務引擎
- 元數據鎖(meta data lock,MDL)
- MySQL5.5版本中引入了MDL,分爲MDL讀鎖和MDL寫鎖。
- 不須要顯式使用,在訪問一個表的時候會被自動加上。
- 事務中的MDL鎖,在語句開始時申請,可是在語句結束後不會立刻釋放,而是等整個事務提交後再釋放。對於長事務,事務不提交,就會一直佔着MDL鎖(重要)
- 做用:保證讀寫的正確性。
- 規則:
- 讀鎖之間不互斥,能夠有多個線程同時對一張表(應該指的是表的元數據)增刪改查。
- 讀寫鎖之間、寫鎖之間是互斥的,用來保證變動表結構操做的安全。若是兩個線程要同時給一個表加字段,其中一個要等另外一個執行完才能開始執行。
- 避坑指南
- 給一個小表加個字段致使整個庫掛了!!!如何安全地給小表加字段?
- 2個知識點:
- 給一個表加字段、或者修改字段、或者加索引,須要掃描全表的數據。
- 事務中的MDL鎖,在語句開始時申請,可是在語句結束後不會立刻釋放,而是等整個事務提交後再釋放。
- 解決方法
- 解決長事務:事務不提交,就會一直佔着MDL鎖。
- 查詢information——schema庫的innodb_trx表中正在執行的長事務,暫停長事務,而後再修改表。
- 對與熱點表的修改,kill事務的方式很差用,能夠在alter table 語句裏設定等待時間。若是在指定的等待時間裏拿到了MDL鎖最好,拿不到也不會阻塞後面的業務語句,先放棄。以後開發人員或者DBA再重試命令。
- MariaDB和AliSQL目前都支持DDL NOWAIT/WAIT n 這個語法
- 行鎖
- 定義:針對數據庫表中行記錄的鎖。
- MySQL的行鎖是引擎層由各個引擎本身實現的。MyISAM引擎不支持行鎖。
- 兩階段鎖協議:在InnoDB事務中,行鎖是在須要的時候才加上的,但並非不須要了就馬上釋放,而是等到事務結束才釋放。
- 建議:若是事務中須要鎖多個行,要把最可能形成鎖衝突、最可能影響併發度的鎖儘可能日後放。
- 死鎖和死鎖檢測
- 解決死鎖的策略
- 一:直接進入等待,直到超時,超時時間經過參數innodb_lock_wati_timeout來設置。InnoDB中,這個值默認是50s,這個值對於在線服務來講,是沒法接受的。把這個值設置成一個小的值也是不合理的。因此不推薦這個方式來解決死鎖。
- 二:發起死鎖檢測,發現死鎖後,主動回滾死鎖鏈條中的某一個事務,讓其餘事務得以繼續執行。設置參數innodb_deadlock_detect=on。InnoDB中,這個值默認就是on,也就是說InnoDB會自動死鎖檢測。
- 每一個新來的被堵住的線程,都要判斷會不會因爲本身的加入致使了死鎖。這是一個時間複雜度爲O(n)的操做。
- 當有1000個線程要同時更新同一行,那麼死鎖檢測操做就是(1000*1000)百萬量級的。雖然最終檢測的結果是沒有死鎖,可是這期間消耗大量的CPU資源。
- 如何解決由熱點行更新致使的性能問題呢?
- 思路一:臨時把死鎖檢測關掉(前提是確保這個業務必定不會出現死鎖)
- 思路二:控制併發度。
- 客戶端作併發控制(當客戶端多的時候不太可行)
- 在中間件中實現,或者修改MySQL源碼,對於向同行的更新,在進入引擎前排隊。這樣InnoDB內部就不會有大量的死鎖檢測工做了。
- 從設計上作優化:將一行改爲邏輯上的多行來減小鎖衝突。(須要根據業務邏輯作詳細設計)
歡迎關注本站公眾號,獲取更多信息