mysql鎖機制詳解及死鎖處理方式

2021-09-20 16:01:09 字數 3925 閱讀 5699

為了給高併發情況下的mysql進行更好的優化,有必要了解一下mysql查詢更新時的鎖表機制。

一、概述

mysql有三種鎖的級別:頁級、表級、行級。

myisam和memory儲存引擎採用的是表級鎖(table-level locking);bdb儲存引擎採用的是頁面鎖(page-level

locking),但也支援表級鎖;innodb儲存引擎既支援行級鎖(row-level locking),也支援表級鎖,但預設情況下是採用行級鎖。

mysql這3種鎖的特性可大致歸納如下:

表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖衝突的概率最高,併發度最低。

行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的概率最低,併發度也最高。

頁面鎖:開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,併發度一般。

二、myisam表鎖

myisam儲存引擎只支援表鎖,是現在用得最多的儲存引擎。

但表級鎖讓多執行緒可以同時從資料表中讀取資料,但是如果另乙個執行緒想要寫資料的話,就必須要先取得排他訪問。正在更新資料時,必須要等到更新完成了,其他執行緒才能訪問這個表。(這種機制造成了併發讀寫容易出現表鎖爭奪而導致阻塞訪問)

1、查詢表級鎖爭用情況

可以通過檢查table_locks_waited和table_locks_immediate狀態變數來分析系統上的表鎖定爭奪:

mysql> show status like 'table%';

+———————–+———-+

| variable_name | value |

+———————–+———-+

| table_locks_immediate | 76939364 |  (表示可以立即獲取鎖的次數)

| table_locks_waited | 305089 | (表示不能立即獲取鎖,需要等待鎖的次數;)

+———————–+———-+

2 rows in set (0.00 sec)

table_locks_waited/(table_locks_immediate+table_locks_waited)

這個比例值越大說明表級鎖爭用的情況越嚴重。

例:比例值=0.01說明100次程序裡就有一次是需要等待鎖的程序;

2、mysql表級鎖的鎖模式

mysql的表級鎖有兩種模式:表共享讀鎖(table read lock)和表獨佔寫鎖(table write

lock)。myisam在執行查詢語句(select)前,會自動給涉及的所有表加讀鎖,在執行更新操作(update、delete、insert等)前,會自動給涉及的表加寫鎖。

所以對myisam表進行操作,會有以下情況:

a、對myisam表的讀操作(加讀鎖),不會阻塞其他程序對同一表的讀請求,但會阻塞對同一表的寫請求。只有當讀鎖釋放後,才會執行其它程序的寫操作。

b、對myisam表的寫操作(加寫鎖),會阻塞其他程序對同一表的讀和寫操作,只有當寫鎖釋放後,才會執行其它程序的讀寫操作。

3、併發插入

原則上資料表有乙個讀鎖時,其它程序無法對此表進行更新操作,但在一定條件下,myisam表也支援查詢和插入操作的併發進行。

myisam儲存引擎有乙個系統變數concurrent_insert,專門用以控制其併發插入的行為,其值分別可以為0、1或2。

a、當concurrent_insert設定為0時,不允許併發插入。

b、當concurrent_insert設定為1時,如果myisam表中沒有空洞(即表的中間沒有被刪除的行),myisam允許在乙個程序讀表的同時,另乙個程序從表尾插入記錄。這也是mysql的預設設定。

c、當concurrent_insert設定為2時,無論myisam表中有沒有空洞,都允許在表尾併發插入記錄。

4、myisam的鎖排程

由於mysql認為寫請求一般比讀請求要重要,所以如果有讀寫請求同時進行的話,mysql將會優先執行寫操作。這樣myisam表在進行大量的更新操作時(特別是更新的字段中存在索引的情況下),會造成查詢操作很難獲得讀鎖,從而導致查詢阻塞。

我們可以通過一些設定來調節myisam的排程行為:

a、通過指定啟動引數low-priority-updates,使myisam引擎預設給予讀請求以優先的權利。

b、通過執行命令set low_priority_updates=1,使該連線發出的更新請求優先順序降低。

c、通過指定insert、update、delete語句的low_priority屬性,降低該語句的優先順序。

上面3種方法都是要麼更新優先,要麼查詢優先的方法。這裡要說明的就是,不要盲目的給mysql設定為讀優先,因為一些需要長時間執行的查詢操作,也會使寫程序「餓死」。只有根據你的實際情況,來決定設定哪種操作優先。

這些方法

還是沒有從根本上同時解決查詢和更新的問題。

在乙個有大資料量高並發表的mysql裡,我們還可採用另一種策略來進行優化,那就是通過mysql主從(讀寫)分離來實現負載均衡,這樣可避免優先哪一種操作從而可能導致另一種操作的堵塞。下面將用乙個篇幅來說明mysql的讀寫分離技術。

myisam使用的是 flock 類的函式,直接就是對整個檔案進行鎖定(叫做檔案鎖定),innodb使用的是 fcntl 類的函式,可以對檔案中區域性資料進行鎖定(叫做行鎖定),所以區別就是在這裡。

另外myisam的資料表是按照單個檔案儲存的,可以針對單個表檔案進行鎖定,但是innodb是一整個檔案,把索引、資料、結構全部儲存在 ibdata 檔案裡,所以必須用行鎖定。

死鎖

所謂死鎖: 是指兩個或兩個以上的程序在執行過程中,

因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去.

此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等竺的程序稱為死鎖程序.

表級鎖不會產生死鎖.所以解決死鎖主要還是真對於最常用的innodb.

遇到死鎖的處理方式

mysql -u*** -p*** -h伺服器ip --port=伺服器端口;(如果伺服器設定了ip和埠訪問的話,一定要帶ip和埠)

mysql> show processlist; #

檢視正在執行的

sql 

(show full processlist;檢視全部sql)

mysql> kill id #

殺死sql

程序;

如果程序太多找不到,就重啟mysql吧

/ect/init.d/mysql restart 

或/ect/init.d/mysql stop(如果關不掉就直接kill -9 程序id)  再/ect/init.d/mysql start 

去看看mysql日誌檔案是否儲存死鎖日誌:

常用目錄:/var/log/mysqld.log;(該目錄還有其它相關日誌檔案就都看看)

怎麼解決還是要看具體什麼問題.

案例記錄(方便日後參考)

1、門店特色產品無法新增、修改;門店店長表無法新增、修改;慢慢整個表都被阻塞;

故障原因:memcache快取伺服器硬碟已滿,無法往快取寫入資料;

表阻塞過程猜測:(以特色產品表為例,該錶型別是myisam)步驟

一、使用者a在更新memcache之前對當前表有查詢操作(可能後台審核特色產品),因為memcache快取伺服器無響應,那麼肯定會等待一些時間,在這個期間內對錶的讀鎖並沒有釋放,使用者a持有讀鎖並處於等待狀態..

步驟二、同一時間段使用者b請求修改或新增特色產品表,但由於使用者a對錶加了讀鎖,使用者b無法獲取寫鎖;使用者b等待寫鎖狀態..

步驟三、使用者c請求查詢新增特色產品表,因為預設是寫操作優先,使用者c處理等待讀鎖狀態..

........(慢慢的更多的查詢請求都被阻塞)

MySQL鎖機制詳解及死鎖處理方式

為了給高併發情況下的mysql進行更好的優化,有必要了解一下mysql查詢更新時的鎖表機制。一 概述 mysql有三種鎖的級別 頁級 表級 行級。myisam和memory儲存引擎採用的是表級鎖 table level locking bdb儲存引擎採用的是頁面鎖 page level lockin...

MySQL鎖機制詳解及死鎖處理方式

為了給高併發情況下的mysql進行更好的優化,有必要了解一下mysql查詢更新時的鎖表機制。一 概述 mysql有三種鎖的級別 頁級 表級 行級。myisam和memory儲存引擎採用的是表級鎖 table level locking bdb儲存引擎採用的是頁面鎖 page level lockin...

Python 互斥鎖 遞迴鎖 死鎖機制詳解

互斥鎖 犧牲了執行效率而獲得資料安全 問題 多個執行緒搶占資源,會發生資料混亂 from threading import thread import os,time def work global n temp n time.sleep 0.1 n temp 1 if name main n 10...