序言
MySQL服務器和獨立的存儲引擎都可以設置鎖。一般來說鎖分為讀鎖(或叫共享鎖)和寫鎖(排它鎖)。讀鎖允許并發線程讀取加鎖的數據,但禁止寫數據;相反,寫鎖禁止其他線程讀寫操作。   
MySQL有4種類型的鎖:表鎖、行鎖、頁鎖、元數據鎖:
表鎖:顧名思義會鎖住整張表,myisam引擎就實現的是表鎖;行鎖:粒度更細,僅鎖住正在被線程訪問的任意一行或多行,因此同一個表中的其他行仍然可以被其他并發線程訪問,innodb引擎是支持行鎖的;頁鎖:僅在少見的BDB引擎中存在,比較少見;元數據鎖:元數據是DDL語句的變更信息,如create、drop、alter等,MySQL 5.5版本加入的新特性。目的是為了解決線程可以在其他線程中的并發事務使用相同表的情況下修改表定義或是刪除表的問題。在并發的環境下極易引起鎖競爭問題,比如獲取鎖等待,也容易導致死鎖。在行鎖級別,死鎖是無法100%避免的,那么當出現鎖問題時,有什么方法定位到原因?又如何解決鎖問題?
定位利器一:show PRocesslist
show processlist可以查看所有正在執行的sql線程:
mysql> show processlist/G*************************** 1. row ***************************     Id: 193   User: root   Host: localhost:51760     db: NULLCommand: Query   Time: 0  State: starting   Info: show processlist輸出字段解釋如下:
Id:執行的線程idUser、Host、db: 客戶端連接的選項Command:線程中執行的命令Time:從線程開始執行命令道現在消耗的時間,單位秒State:內部狀態Info:表明線程當前正在進行的工作推薦使用查詢 select * from information_schema.processlist表,輸出結果和show processlist完全一致,不過由于保持在表中可以根據需要排序查詢結果,如果按特定User或者按執行時間排序等。
  獲取查詢執行時間最長的10個線程   select * from information_schema.processlist order by Time desc limit 10/G
通過這個show processlist利器,可以很直觀看出異常線程,及對應執行的sql,一目了然。
利器二:show engine innodb status
這個利器是專門針對Innodb引擎的,可以確定InnoDB中的請求是否阻塞。該命令在分析并發多語句事務的作用的時候尤為有用,輸出內容更加詳細。
  show engine innodb status
輸出信息比較多,對于鎖和事務相關的重點關注TRANSACTIONS以下部分:
------------TRANSACTIONS------------Trx id counter 10753Purge done for trx's n:o < 10729 undo n:o < 0 state: running but idleHistory list length 700LIST OF TRANSACTIONS FOR EACH session:---TRANSACTION 422098131918480, not started0 lock struct(s), heap size 1136, 0 row lock(s)---TRANSACTION 10752, ACTIVE 12 sec starting index readmysql tables in use 1, locked 1LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s)MySQL thread id 211, OS thread handle 140622868731648, query id 10380 localhost 127.0.0.1 root updatingupdate  t_attr2 set id=213 where id=212------- TRX HAS BEEN WAITING 12 SEC FOR THIS LOCK TO BE GRANTED:RECORD LOCKS space id 124 page no 7 n bits 96 index PRIMARY of table `wechat`.`t_attr2` trx id 10752 lock_mode X locks rec but not gap waitingRecord lock, heap no 23 PHYSICAL RECORD: n_fields 8; compact format; info bits 32 0: len 8; hex 80000000000000d4; asc         ;; 1: len 6; hex 0000000029fd; asc     ) ;; 2: len 7; hex 25000001430c75; asc %   C u;; 3: len 30; hex 687474703a2f2f777566617a7563652e636f6d2f73656c6563742e68746d; asc http://wufazuce.com/select.htm; (total 31 bytes); 4: len 20; hex 3131352e3139372e3234362e3533202020202020; asc 115.197.246.53      ;; 5: len 30; hex e4b8ade59bbde58d8ee4b89ce6b599e6b19fe79c81e69dade5b79ee5b882; asc                               ; (total 36 bytes); 6: len 30; hex 4d6f7a696c6c612f352e30202857696e646f7773204e5420362e313b2057; asc Mozilla/5.0 (Windows NT 6.1; W; (total 126 bytes); 7: len 4; hex 58ab9f58; asc X  X;;---------------------TRANSACTION 10749, ACTIVE 94 sec2 lock struct(s), heap size 1136, 1 row lock(s), undo log entries 2MySQL thread id 210, OS thread handle 140622868932352, query id 10008 localhost 127.0.0.1 root cleaning up從上面的信息可以很容易看到事務的信息,包括執行的時長,執行的sql語句,線程id,查詢id等;
相關參數和觀察表
最后介紹有幾個和鎖、事務有關的參數及系統表: - innodb_wait_timeout參數:innodb獲取鎖等待超時時間,默認50秒; - INFORMATION_SCHEMA.innodb_locks表:保持已獲得鎖的信息; - INFORMATION_SCHEMA.innodb_lock_waits表:保持等待鎖的信息; - INFORMATION_SCHEMA.innodb_trx表:保持正在執行的事務的信息
總結
在MySQL并發條件下出現鎖搶占或死鎖的很常見的,遇到鎖問題當務之急是定位出現問題的線程,再定位出正在執行的sql,那么修復就很簡單了。一般來說,為了避免鎖搶占或死鎖的出現,一定要保持事務短小精悍。