自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

MySQL鎖等待與死鎖問題分析

數據庫 MySQL
出現鎖等待或死鎖的原因是訪問數據庫需要加鎖,那你可能要問了,為啥要加鎖呢?原因是為了確保并發(fā)更新場景下的數據正確性,保證數據庫事務的隔離性。

 [[389778]]

本文轉載自微信公眾號「MySQL技術」,作者MySQL技術。轉載本文請聯(lián)系MySQL技術公眾號。

前言:

在 MySQL 運維過程中,鎖等待和死鎖問題是令各位 DBA 及開發(fā)同學非常頭痛的事。出現此類問題會造成業(yè)務回滾、卡頓等故障,特別是業(yè)務繁忙的系統(tǒng),出現死鎖問題后影響會更嚴重。本篇文章我們一起來學習下什么是鎖等待及死鎖,出現此類問題又應該如何分析處理呢?

1.了解鎖等待與死鎖

出現鎖等待或死鎖的原因是訪問數據庫需要加鎖,那你可能要問了,為啥要加鎖呢?原因是為了確保并發(fā)更新場景下的數據正確性,保證數據庫事務的隔離性。

試想一個場景,如果你要去圖書館借一本《高性能MySQL》,為了防止有人提前把這本書借走,你可以提前進行預約(加鎖),這把鎖可以怎么加?

  • 封鎖圖書館(數據庫級別的鎖)
  • 把數據庫相關的書都鎖住(表級別的鎖)
  • 只鎖 MySQL 相關的書(頁級別的鎖)
  • 只鎖《高性能MySQL》這本書(行級別的鎖)

鎖的粒度越細,并發(fā)級別越高,實現也更復雜。

鎖等待也可稱為事務等待,后執(zhí)行的事務等待前面處理的事務釋放鎖,但是等待時間超過了 MySQL 的鎖等待時間,就會引發(fā)這個異常。等待超時后的報錯為“Lock wait timeout exceeded...”。

死鎖發(fā)生的原因是兩個事務互相等待對方釋放相同資源的鎖,從而造成的死循環(huán)。產生死鎖后會立即報錯“Deadlock found when trying to get lock...”。

2.現象復現及處理

下面我們以 MySQL 5.7.23 版本為例(隔離級別是 RR ),來復現下上述兩種異?,F象。

  1. mysql> show create table test_tb\G 
  2. *************************** 1. row *************************** 
  3.        Table: test_tb 
  4. Create TableCREATE TABLE `test_tb` ( 
  5.   `id` int(11) NOT NULL AUTO_INCREMENT, 
  6.   `col1` varchar(50) NOT NULL DEFAULT ''
  7.   `col2` int(11) NOT NULL DEFAULT '1'
  8.   `col3` varchar(20) NOT NULL DEFAULT ''
  9.   PRIMARY KEY (`id`), 
  10.   KEY `idx_col1` (`col1`) 
  11. ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 
  12. 1 row in set (0.00 sec) 
  13.  
  14. mysql> select * from test_tb; 
  15. +----+------+------+------+ 
  16. | id | col1 | col2 | col3 | 
  17. +----+------+------+------+ 
  18. |  1 | fdg  |    1 | abc  | 
  19. |  2 | a    |    2 | fg   | 
  20. |  3 | ghrv |    2 | rhdv | 
  21. +----+------+------+------+ 
  22. rows in set (0.00 sec) 
  23.  
  24. # 事務一首先執(zhí)行 
  25. mysql> begin
  26. Query OK, 0 rows affected (0.00 sec) 
  27.  
  28. mysql> select * from test_tb where col1 = 'a' for update
  29. +----+------+------+------+ 
  30. | id | col1 | col2 | col3 | 
  31. +----+------+------+------+ 
  32. |  2 | a    |    2 | fg   | 
  33. +----+------+------+------+ 
  34. 1 row in set (0.00 sec) 
  35.  
  36. # 事務二然后執(zhí)行 
  37. mysql> begin
  38. Query OK, 0 rows affected (0.01 sec) 
  39.  
  40. mysql> update test_tb set col2 = 1 where col1 = 'a'
  41. ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction 

出現上種異常的原因是事務二在等待事務一的行鎖,但事務一一直沒提交,等待超時而報錯。InnoDB 行鎖等待超時時間由 innodb_lock_wait_timeout 參數控制,此參數默認值為 50 ,單位為秒,即默認情況下,事務二會等待 50s ,若仍拿不到行鎖則會報等待超時異常并回滾此條語句。

對于 5.7 版本,出現鎖等待時,我們可以查看 information_schema 中的幾張系統(tǒng)表來查詢事務狀態(tài)。

  • innodb_trx 當前運行的所有事務。
  • innodb_locks 當前出現的鎖。
  • innodb_lock_waits 鎖等待的對應關系
  1. # 鎖等待發(fā)生時 查看innodb_trx表可以看到所有事務  
  2. # trx_state值為LOCK WAIT 則代表該事務處于等待狀態(tài) 
  3.  
  4. mysql> select * from information_schema.innodb_trx\G 
  5. *************************** 1. row *************************** 
  6.                     trx_id: 38511 
  7.                  trx_state: LOCK WAIT 
  8.                trx_started: 2021-03-24 17:20:43 
  9.      trx_requested_lock_id: 38511:156:4:2 
  10.           trx_wait_started: 2021-03-24 17:20:43 
  11.                 trx_weight: 2 
  12.        trx_mysql_thread_id: 1668447 
  13.                  trx_query: update test_tb set col2 = 1 where col1 = 'a' 
  14.        trx_operation_state: starting index read 
  15.          trx_tables_in_use: 1 
  16.          trx_tables_locked: 1 
  17.           trx_lock_structs: 2 
  18.      trx_lock_memory_bytes: 1136 
  19.            trx_rows_locked: 1 
  20.          trx_rows_modified: 0 
  21.    trx_concurrency_tickets: 0 
  22.        trx_isolation_level: REPEATABLE READ 
  23.          trx_unique_checks: 1 
  24.     trx_foreign_key_checks: 1 
  25. trx_last_foreign_key_error: NULL 
  26.  trx_adaptive_hash_latched: 0 
  27.  trx_adaptive_hash_timeout: 0 
  28.           trx_is_read_only: 0 
  29. trx_autocommit_non_locking: 0 
  30. *************************** 2. row *************************** 
  31.                     trx_id: 38510 
  32.                  trx_state: RUNNING 
  33.                trx_started: 2021-03-24 17:18:54 
  34.      trx_requested_lock_id: NULL 
  35.           trx_wait_started: NULL 
  36.                 trx_weight: 4 
  37.        trx_mysql_thread_id: 1667530 
  38.                  trx_query: NULL 
  39.        trx_operation_state: NULL 
  40.          trx_tables_in_use: 0 
  41.          trx_tables_locked: 1 
  42.           trx_lock_structs: 4 
  43.      trx_lock_memory_bytes: 1136 
  44.            trx_rows_locked: 3 
  45.          trx_rows_modified: 0 
  46.    trx_concurrency_tickets: 0 
  47.        trx_isolation_level: REPEATABLE READ 
  48.          trx_unique_checks: 1 
  49.     trx_foreign_key_checks: 1 
  50. trx_last_foreign_key_error: NULL 
  51.  trx_adaptive_hash_latched: 0 
  52.  trx_adaptive_hash_timeout: 0 
  53.           trx_is_read_only: 0 
  54. trx_autocommit_non_locking: 0 
  55. rows in set (0.00 sec) 
  56.  
  57. # innodb_trx 字段值含義 
  58. trx_id:事務ID。 
  59. trx_state:事務狀態(tài),有以下幾種狀態(tài):RUNNING、LOCK WAIT、ROLLING BACK 和 COMMITTING。 
  60. trx_started:事務開始時間。 
  61. trx_requested_lock_id:事務當前正在等待鎖的標識,可以和 INNODB_LOCKS 表 JOIN 以得到更多詳細信息。 
  62. trx_wait_started:事務開始等待的時間。 
  63. trx_weight:事務的權重。 
  64. trx_mysql_thread_id:事務線程 ID,可以和 PROCESSLIST 表 JOIN。 
  65. trx_query:事務正在執(zhí)行的 SQL 語句。 
  66. trx_operation_state:事務當前操作狀態(tài)。 
  67. trx_tables_in_use:當前事務執(zhí)行的 SQL 中使用的表的個數。 
  68. trx_tables_locked:當前執(zhí)行 SQL 的行鎖數量。 
  69. trx_lock_structs:事務保留的鎖數量。 
  70. trx_isolation_level:當前事務的隔離級別。 
  71.  
  72. # sys.innodb_lock_waits 視圖也可看到事務等待狀況,且給出了殺鏈接的SQL 
  73. mysql> select * from sys.innodb_lock_waits\G 
  74. *************************** 1. row *************************** 
  75.                 wait_started: 2021-03-24 17:20:43 
  76.                     wait_age: 00:00:22 
  77.                wait_age_secs: 22 
  78.                 locked_table: `testdb`.`test_tb` 
  79.                 locked_index: idx_col1 
  80.                  locked_type: RECORD 
  81.               waiting_trx_id: 38511 
  82.          waiting_trx_started: 2021-03-24 17:20:43 
  83.              waiting_trx_age: 00:00:22 
  84.      waiting_trx_rows_locked: 1 
  85.    waiting_trx_rows_modified: 0 
  86.                  waiting_pid: 1668447 
  87.                waiting_query: update test_tb set col2 = 1 where col1 = 'a' 
  88.              waiting_lock_id: 38511:156:4:2 
  89.            waiting_lock_mode: X 
  90.              blocking_trx_id: 38510 
  91.                 blocking_pid: 1667530 
  92.               blocking_query: NULL 
  93.             blocking_lock_id: 38510:156:4:2 
  94.           blocking_lock_mode: X 
  95.         blocking_trx_started: 2021-03-24 17:18:54 
  96.             blocking_trx_age: 00:02:11 
  97.     blocking_trx_rows_locked: 3 
  98.   blocking_trx_rows_modified: 0 
  99.      sql_kill_blocking_query: KILL QUERY 1667530 
  100. sql_kill_blocking_connection: KILL 1667530 

sys.innodb_lock_waits 視圖整合了事務等待狀況,同時給出殺掉堵塞源端的 kill 語句。不過是否要殺掉鏈接還是需要綜合考慮的。

死鎖與鎖等待稍有不同,我們同樣也來簡單復現下死鎖現象。

  1. # 開啟兩個事務 
  2. # 事務一執(zhí)行 
  3. mysql> update test_tb set col2 = 1 where col1 = 'a'
  4. Query OK, 1 row affected (0.00 sec) 
  5. Rows matched: 1  Changed: 1  Warnings: 0 
  6.  
  7. # 事務二執(zhí)行 
  8. mysql> update test_tb set col2 = 1 where id = 3; 
  9. Query OK, 1 row affected (0.00 sec) 
  10. Rows matched: 1  Changed: 1  Warnings: 0 
  11.  
  12. # 回到事務一執(zhí)行 回車后 此條語句處于鎖等待狀態(tài) 
  13. mysql> update test_tb set col1 = 'abcd' where id = 3; 
  14. Query OK, 1 row affected (5.71 sec) 
  15. Rows matched: 1  Changed: 1  Warnings: 0 
  16.  
  17. # 回到事務二再執(zhí)行 此時二者相互等待發(fā)生死鎖 
  18. mysql> update test_tb set col3 = 'gddx' where col1 = 'a'
  19. ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction 

發(fā)生死鎖后會選擇一個事務進行回滾,想查明死鎖原因,可以執(zhí)行 show engine innodb status 來查看死鎖日志,根據死鎖日志,結合業(yè)務邏輯來進一步定位死鎖原因。

在實際應用中,我們要盡量避免死鎖現象的發(fā)生,可以從以下幾個方面入手:

  • 事務盡可能小,不要講復雜邏輯放進一個事務里。
  • 涉及多行記錄時,約定不同事務以相同順序訪問。
  • 業(yè)務中要及時提交或者回滾事務,可減少死鎖產生的概率。
  • 表要有合適的索引。
  • 可嘗試將隔離級別改為 RC 。

總結:

本篇文章簡單介紹了鎖等待及死鎖發(fā)生的原因,其實真實業(yè)務中發(fā)生死鎖還是很難分析的,需要一定的經驗積累。本篇文章只是面向初學者,希望各位對死鎖能夠有個初印象。

 

責任編輯:武曉燕 來源: MySQL技術
相關推薦

2020-04-23 11:43:55

MySQL數據庫SQL

2010-06-30 14:15:08

SQL Server死

2017-06-07 16:10:24

Mysql死鎖死鎖日志

2010-08-10 13:36:00

2020-04-14 10:20:12

MySQL數據庫死鎖

2024-10-16 11:40:47

2024-10-30 10:38:08

2011-08-24 17:41:16

MySQL死鎖

2010-08-02 17:30:30

DB2鎖等待

2025-03-03 04:00:00

線程安全CPU

2017-06-14 22:11:57

數據庫MySQL死鎖

2010-08-19 09:54:42

DB2死鎖

2010-08-10 08:42:35

DB2鎖等待

2021-07-04 22:29:12

MySQL死鎖云日志

2010-08-20 08:52:25

DB2死鎖

2021-06-08 08:38:36

MySQL數據庫死鎖問題

2018-07-31 10:10:06

MySQLInnoDB死鎖

2020-07-16 21:20:08

數據庫MySQL死鎖

2017-05-03 16:26:24

MySQL并發(fā)死鎖

2011-03-07 09:05:49

鎖競爭MySQL等待時間
點贊
收藏

51CTO技術棧公眾號