1. 程式人生 > >Mysql的共享鎖(S 鎖)&排他鎖(X 鎖)&死鎖的產生與解決辦法

Mysql的共享鎖(S 鎖)&排他鎖(X 鎖)&死鎖的產生與解決辦法

表級鎖

MySQL表級鎖分為讀鎖和寫鎖。

讀鎖

用法:LOCK TABLE table_name [ AS alias_name ] READ

釋放鎖使用UNLOCK tables.可以為表使用別名,如果一旦使用別名在使用的時候也必須採用別名。成功申請讀鎖的前提是當前沒有執行緒對該表使用寫鎖,否則該語句會被阻塞。申請讀鎖成功後,其他執行緒也可以對該表進行讀操作,但不允許有執行緒對其進行寫操作,就算是當前執行緒也不允許。當鎖住了A表之後,就只能對A表進行讀操作,對其他表進行讀操作會出現錯誤(tablename was not locked with LOCK TABLES)

user表中有一條資料記錄:

travelrecord中有一條資料記錄:

在鎖定了tb_user表後,再去查詢travelrecord表,此時的查詢報錯:

如果此時,在另外一個session中進行更新操作:

update tb_user set name = 'hand1' where id = 6

則一直處於阻塞狀態:

寫鎖

用法: LOCK TABLE table_name [AS alias_name] [ LOW_PRIORITY ] WRITE

同樣也可以使用別名,與讀鎖不同的是,寫鎖中可以指定鎖的優先順序。LOW_PRIORITY是一種比讀鎖更低優先順序的鎖,當多個執行緒同時申請多種鎖(LOW_PRIORITY,READ,WRITE)時,LOW_PRIORITY的優先順序最低。讀鎖申請成功的前提是沒有執行緒對錶加讀鎖和其他寫鎖,否則會被阻塞。

表級鎖在MyISAM和innoDB中都有用到,建立鎖的開銷小,不會出現死鎖,由於鎖定的是整張表,所以併發度低。當需要頻繁對大部分資料做 GROUP BY 操作或者需要頻繁掃描整個表時,推薦使用表級鎖。

行級鎖

行級鎖是Mysql中鎖定粒度最細的一種鎖,能大大減少資料庫操作的衝突,由於其粒度小,加鎖的開銷最大。行級鎖分為共享鎖和排他鎖。

共享鎖(S LOCK)

用法:SELECT ...LOCK IN SHARE MODE;

Mysql會對查詢結果中的每行都加共享鎖,當沒有其他執行緒對查詢結果集中的任何一行使用排他鎖時,可以成功申請共享鎖,否則會被阻塞。其他執行緒也可以讀取使用了共享鎖的表,而且這些執行緒讀取的是同一個版本的資料。

排他鎖(X LOCK)

用法:SELECT ...LOCK FOR UPDATE;

Mysql會對查詢結果中的每行都加排他鎖,當沒有其他執行緒對查詢結果集中的任何一行使用排他鎖時,可以成功申請排他鎖,否則會被阻塞。

行級鎖都是基於索引的,如果一條SQL語句用不到索引是不會使用行級鎖的,會使用表級鎖。行級鎖的缺點是:由於需要請求大量的鎖資源,所以速度慢,記憶體消耗大。

死鎖

概念:

死鎖是指兩個或兩個以上的程序在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去.此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等的程序稱為死鎖程序.

產生條件:

  • 互斥條件:指程序對所分配到的資源進行排它性使用,即在一段時間內某資源只由一個程序佔用。如果此時還有其它程序請求資源,則請求者只能等待,直至佔有資源的程序用畢釋放
  • 請求和保持條件:指程序已經保持至少一個資源,但又提出了新的資源請求,而該資源已被其它程序佔有,此時請求程序阻塞,但又對自己已獲得的其它資源保持不放
  • 不剝奪條件:指程序已獲得的資源,在未使用完之前,不能被剝奪,只能在使用完時由自己釋放
  • 環路等待條件:指在發生死鎖時,必然存在一個程序——資源的環形鏈,即程序集合{P0,P1,P2,···,Pn}中的P0正在等待一個P1佔用的資源;P1正在等待P2佔用的資源,……,Pn正在等待已被P0佔用的資源

遇到死鎖可以執行如下的查詢語句觀察等待的事務:

-- 檢視當前的事務
select * from information_schema.innodb_trx;
-- 檢視當前鎖定的事務
select * from information_schema.innodb_locks;
-- 檢視當前等鎖的事務
select * from information_schema.innodb_lock_waits;

也可以執行如下的查詢將死鎖的日誌匯出:

show engine innodb status