MySQL中的鎖

MySQL有三種鎖的級別:mysql

1)表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖衝突的機率最高,併發度最低。
2)行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的機率最低,併發度也最高。
3)頁面鎖:開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,併發度通常。
4)InnoDB行級鎖的實現:InnoDB的行級鎖是經過在索引上加鎖來實現的,因此只有經過明確的索引來查找數據時纔會使用行級鎖!換句話說就是:若是在執行sql時沒有用到索引,則mysql就沒法使用行鎖了。

MySQL中鎖的類型:sql

共享鎖(S鎖:Shared lock)
	1)共享鎖又叫讀鎖,MySQL會在select ... lock in share mode語句的查詢結果集上添加共享鎖;
	2)共享鎖能夠被多個事務同時持有。
	3)某個事務在涉及的數據行加上共享鎖後,全部的事務只能對這些數據進行讀操做,目的是爲了防止在讀取數據的過程當中,其它事務對數據進行修改。
	4)不能在共享鎖的基礎上再加其它類型的鎖。
	

獨佔鎖(X鎖:Exclusive lock)
	1)獨佔鎖又叫排它鎖,InnoDB引擎默認會給insert、delete、update、select ... for update 等語句加上獨佔鎖。
	2)獨佔鎖只能被一個事務獲取,其它事務只有等到持有獨佔鎖的事務將鎖釋放後,才能去獲取獨佔鎖。
	3)某個事務在涉及的數據行加上獨佔鎖後,這個事務就能夠對鎖定這些數據進行修改操做了。
	4)不能在獨佔鎖的基礎上再加其它類型的鎖。
	
	共享鎖和獨佔鎖能夠加在表、頁、數據行(索引)上。
	
	
排它鎖的選擇:

	若where條件中明確指定了主鍵,且該行數據存在,則只鎖定該行,故排它鎖爲行鎖(row lock)。
	若where條件中明確指定了主鍵,可是該行數據不存在,則不會加鎖。
	
	若where條件中明確指定了索引,且該行數據存在,則只鎖定該行,故排它鎖爲行鎖(row lock)。
	若where條件中明確指定了索引,可是該行數據不存在,則不會加鎖。
	
	若where條件中未明確指定主鍵或索引,則會鎖定全表,故排它鎖爲表鎖(table lock)。換句話說就是:在執行sql時沒有用到索引!!!
	注:未明確指定 即 未指定(主鍵/索引) 或 指定的是(主鍵/索引)的範圍
		
	eg:
		# 只鎖定message_id爲1的行
		set autocommit=0;
		begin;
		select * from t_message where message_id=1 for update; # message_id爲主鍵
		commit;

		# 鎖定全表
		set autocommit=0;
		begin;
		select * from t_message where message_id>1 for update; # message_id爲主鍵
		commit;
		
		# 鎖定全表
		set autocommit=0;
		begin;
		select * from t_message where type='good' for update; # good非索引列
		commit;


	其它線程由於等待(排它鎖)超時而報錯:
	update t_message set title='asdf' where message_id=1;
	[Err] 1205 - Lock wait timeout exceeded; try restarting transaction

死鎖產生的四個必要條件:數據庫

互斥條件	資源只能由一個線程使用
請求保持	保持已鎖定的資源不釋放
不可剝奪	已持有的資源不會被其它線程剝奪
環路條件	循環等待

避免死鎖:併發

說明:致使死鎖的常見場景:兩個Connection中加鎖的順序不一致。

1)不一樣的方法併發存取多個表時,儘可能以相同的順序訪問這些表。
2)在一個事務中,儘可能一次性鎖定所需的全部資源,即一次性鎖定多行。

排查死鎖:spa

1)show processlist

	運行時間最大的(即:Time值最大)的線程最有多是致使死鎖的線程。


2)MySQL中information_schema數據庫中關於Innodb事務和鎖的三張表:

	select * from information_schema.INNODB_TRX
	select * from information_schema.INNODB_LOCKS
	select * from information_schema.INNODB_LOCK_WAITS


3)show engine innodb status


4)kill MySQL線程Id

Tips: 在select後面添加sleep(n)後,該sql最少會執行n秒;若查詢結果爲m行,則該sql最少會執行m*n秒。 eg:select sleep(5),t.name from t_user t where t.age=1線程

MySQL中information_schema數據庫中關於Innodb事務和鎖的三張表:rest

1)查看在InnoDB引擎中正在執行的事務,包括:正在執行的事務 和 因申請加鎖而等待的事務。
	SQL:select * from information_schema.INNODB_TRX
	
	trx_id					事務的ID
	trx_state				事務的狀態: RUNNING, LOCK WAIT, ROLLING BACK or COMMITTING.
	trx_started				事務的開始時間
	trx_requested_lock_id	事務等待的鎖的ID(若是事務狀態不是LOCK WAIT,這個字段是NULL),詳細的鎖的信息能夠連查INNODB_LOCKS表
	trx_wait_started		事務等待開始的時間(若是事務狀態不是LOCK WAIT,這個字段是NULL)
	trx_weight				事務的權重,反映了一個事務修改和鎖住的行數。當發生死鎖回滾的時候,優先選擇該值最小的進行回滾。
	trx_mysql_thread_id		MySQL中的線程ID,show processlist結果中的Id列。
	trx_query				事務中正在運行的sql語句
	trx_operation_state		事務當操做的類型
	trx_tables_in_use		查詢用到的表的數量
	trx_tables_locked		查詢加行鎖的表的數量


2)查看在InnoDB引擎中存在的鎖,包括:事務正在申請的鎖 和 事務已經持有的鎖。
	SQL:select * from information_schema.INNODB_LOCKS

	lock_id		鎖ID
	lock_trx_id	事務ID,能夠連INNODB_TRX表查事務詳情
	lock_mode	鎖的模式: S, X, IS, IX, S_GAP, X_GAP, IS_GAP, IX_GAP, or AUTO_INC
	lock_type	鎖的類型:行級鎖 或 表級鎖
	lock_table	加鎖的表
	lock_index	若是是lock_type='RECORD' 行級鎖,爲鎖住的索引,若是是表鎖爲null
	lock_space	若是是lock_type='RECORD' 行級鎖,爲鎖住對象的Tablespace ID,若是是表鎖爲null
	lock_page	若是是lock_type='RECORD' 行級鎖,爲鎖住頁號,若是是表鎖爲null
	lock_rec	若是是lock_type='RECORD' 行級鎖,爲鎖住行號,若是是表鎖爲null
	lock_data	事務鎖住的主鍵值,如果表鎖,則該值爲null

	
3)查看在InnoDB引擎中鎖等待的相關信息:
	SQL:select * from information_schema.INNODB_LOCK_WAITS
	
	requesting_trx_id	申請鎖的事務ID
	requesting_lock_id	申請的鎖的ID
	blocking_trx_id		阻塞的事務ID
	blocking_lock_id	阻塞的鎖的ID

show open tables where in_use > 0 Database 數據庫 Table 表名 In_use 正在訪問該表的線程數 Name_locked 表名是否被鎖(Drop或Rename這張表時,表名會被鎖住)code

相關文章
相關標籤/搜索