如果遇到死鎖了,怎麼解決呢?找到原始的鎖ID,然後KILL掉一直持有的那個執行緒就可以了, 但是眾多執行緒,可怎麼找到引起死鎖的執行緒ID呢? MySQL 發展到現在,已經非常強大了,這個問題很好解決。 直接從資料字典連查詢。

 
我們來演示下。

執行緒A,我們用來鎖定某些記錄,假設這個執行緒一直沒提交,或者忘掉提交了。 那麼就一直存在,但是資料裡面顯示的只是SLEEP狀態。
 
 
 
  1. mysql> set @@autocommit=0; 
  2. Query OK, 0 rows affected (0.00 sec) 
  3.  
  4. mysql> use test; 
  5. Reading table information for completion of table and column names 
  6. You can turn off this feature to get a quicker startup with -A 
  7.  
  8. Database changed 
  9. mysql> show tables; 
  10. +----------------+ 
  11. | Tables_in_test | 
  12. +----------------+ 
  13. | demo_test      | 
  14. | t3             | 
  15. +----------------+ 
  16. rows in set (0.00 sec) 
  17.  
  18. mysql> select * from t3; 
  19. +----+--------+--------+------------+----+----+----+ 
  20. | id | fname  | lname  | birthday   | c1 | c2 | c3 | 
  21. +----+--------+--------+------------+----+----+----+ 
  22. | 19 | lily19 | lucy19 | 2013-04-18 | 19 |  0 |  0 | 
  23. | 20 | lily20 | lucy20 | 2013-03-13 | 20 |  0 |  0 | 
  24. +----+--------+--------+------------+----+----+----+ 
  25. rows in set (0.00 sec) 
  26.  
  27. mysql> update t3 set birthday = `2022-02-23` where id = 19; 
  28. Query OK, 1 row affected (0.00 sec) 
  29. Rows matched: 1  Changed: 1  Warnings: 0 
  30.  
  31. mysql> select connection_id(); 
  32. +-----------------+ 
  33. | connection_id() | 
  34. +-----------------+ 
  35. |              16 | 
  36. +-----------------+ 
  37. 1 row in set (0.00 sec) 
  38.  
  39. mysql>  
 
執行緒B, 我們用來進行普通的更新,但是遇到問題了,此時不知道是哪個執行緒把這行記錄給鎖定了?
 
 
  1. mysql> use test; 
  2. Reading table information for completion of table and column names 
  3. You can turn off this feature to get a quicker startup with -A 
  4.  
  5. Database changed 
  6. mysql> select @@autocommit; 
  7. +--------------+ 
  8. | @@autocommit | 
  9. +--------------+ 
  10. |            1 | 
  11. +--------------+ 
  12. 1 row in set (0.00 sec) 
  13.  
  14. mysql> update t3 set birthday=`2018-01-03` where id = 19; 
  15. ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction 
  16. mysql> select connection_id(); 
  17. +-----------------+ 
  18. | connection_id() | 
  19. +-----------------+ 
  20. |              17 | 
  21. +-----------------+ 
  22. 1 row in set (0.00 sec) 
  23.  
  24. mysql> show processlist; 
  25. +----+------+-----------+------+---------+------+-------+------------------+ 
  26. | Id | User | Host      | db   | Command | Time | State | Info             | 
  27. +----+------+-----------+------+---------+------+-------+------------------+ 
  28. | 10 | root | localhost | NULL | Sleep   | 1540 |       | NULL             | 
  29. | 11 | root | localhost | NULL | Sleep   |  722 |       | NULL             | 
  30. | 16 | root | localhost | test | Sleep   |  424 |       | NULL             | 
  31. | 17 | root | localhost | test | Query   |    0 | init  | show processlist | 
  32. | 18 | root | localhost | NULL | Sleep   |    5 |       | NULL             | 
  33. +----+------+-----------+------+---------+------+-------+------------------+ 
  34. rows in set (0.00 sec) 
  35.  
  36. mysql> show engine innodb statusG 
  37.  
  38.  
  39. ------------ 
  40. TRANSACTIONS 
  41. ------------ 
  42. Trx id counter 189327 
  43. Purge done for trx`s n:o < 189323 undo n:o < 0 state: running but idle 
  44. History list length 343 
  45. LIST OF TRANSACTIONS FOR EACH SESSION: 
  46. ---TRANSACTION 0, not started 
  47. MySQL thread id 11, OS thread handle 0x7f70a0c98700, query id 994 localhost root init 
  48. show engine innodb status 
  49. ---TRANSACTION 189326, ACTIVE 2 sec starting index read 
  50. mysql tables in use 1, locked 1 
  51. LOCK WAIT 2 lock struct(s), heap size 376, 1 row lock(s) 
  52. MySQL thread id 17, OS thread handle 0x7f70a0bd5700, query id 993 localhost root updating 
  53. update t3 set birthday=`2018-01-03` where id = 19 
  54. ------- TRX HAS BEEN WAITING 2 SEC FOR THIS LOCK TO BE GRANTED: 
  55. RECORD LOCKS space id 529 page no 3 n bits 72 index `PRIMARYof table `test`.`t3` trx id 189326 lock_mode X waiting 
  56. Record lock, heap no 2 PHYSICAL RECORD: n_fields 9; compact format; info bits 0 
  57.  0: len 2; hex 3139; asc 19;; 
  58.  1: len 6; hex 00000002e38c; asc       ;; 
  59.  2: len 7; hex 7e00000d2827c9; asc ~   (` ;; 
  60.  3: len 6; hex 6c696c793139; asc lily19;; 
  61.  4: len 6; hex 6c7563793139; asc lucy19;; 
  62.  5: len 3; hex 8fcc57; asc   W;; 
  63.  6: len 4; hex 80000013; asc     ;; 
  64.  7: len 4; hex 80000000; asc     ;; 
  65.  8: len 4; hex 80000000; asc     ;; 
  66.  
  67. ------------------ 
  68. ---TRANSACTION 189324, ACTIVE 641 sec 
  69. 2 lock struct(s), heap size 376, 3 row lock(s), undo log entries 1 
  70. MySQL thread id 16, OS thread handle 0x7f70a0b94700, query id 985 localhost root cleaning up 
  71. Trx read view will not see trx with id >= 189325, sees < 189325 
 
上面的資訊很繁多,也看不清楚到底哪裡是哪裡。
 
不過現在,我們只要從資料字典裡面拿出來這部分資訊就OK了。
 
 
  1. mysql> SELECT * FROM information_schema.INNODB_TRXG 
  2. *************************** 1. row *************************** 
  3.                     trx_id: 189324 
  4.                  trx_state: RUNNING 
  5.                trx_started: 2013-04-18 17:48:14 
  6.      trx_requested_lock_id: NULL 
  7.           trx_wait_started: NULL 
  8.                 trx_weight: 3 
  9.        trx_mysql_thread_id: 16 
  10.                  trx_query: NULL 
  11.        trx_operation_state: NULL 
  12.          trx_tables_in_use: 0 
  13.          trx_tables_locked: 0 
  14.           trx_lock_structs: 2 
  15.      trx_lock_memory_bytes: 376 
  16.            trx_rows_locked: 3 
  17.          trx_rows_modified: 1 
  18.    trx_concurrency_tickets: 0 
  19.        trx_isolation_level: REPEATABLE READ 
  20.          trx_unique_checks: 1 
  21.     trx_foreign_key_checks: 1 
  22. trx_last_foreign_key_error: NULL 
  23.  trx_adaptive_hash_latched: 0 
  24.  trx_adaptive_hash_timeout: 10000 
  25.           trx_is_read_only: 0 
  26. trx_autocommit_non_locking: 0 
  27. 1 row in set (0.01 sec) 
  28.  
  29. mysql>  
 
原來是執行緒16忘掉COMMIT了。