一、錯誤發生及原因猜測
1、錯誤發生
在刪除 t_user 表的一條數據時,Navicat 發生長時間的無響應,然后彈出一個對話框,提示:ERROR 1205: Lock wait timeout exceeded; try restarting transaction
關閉對話框之后,數據並沒有被刪除。
2、原因猜測
根據錯誤信息可以知道,是因為鎖等待超時導致的錯誤。那么具體到底是什么原因。
我們知道,InnoDB 引擎是支持事務的。
在使用 begin 或 start transaction 開啟事務,進行更新、刪除時,會對被操作的行加行級鎖。
如果這個事務沒有提交,而其他的事務對同一行也進行了更新、刪除操作,那么這個事務是不能成功的,至於會不會出現上面的錯誤,還不確定。
二、錯誤重現
1、演示環境
操作系統 |
Windows 7 x64 |
MySQL版本 |
MySQL Community Server (GPL) 5.5.56 |
執行未提交事務的用戶 |
system |
查看會話、執行刪除操作的用戶 |
root |
數據庫 |
test |
表 |
t_user |
1 mysql> select * from t_user; 2 +----+----------+ 3 | id | username | 4 +----+----------+ 5 | 1 | a1 | 6 | 2 | a2 | 7 | 3 | a3 | 8 | 4 | a4 | 9 | 5 | a5 | 10 | 6 | a6 | 11 +----+----------+
2、錯誤重現
使用 A窗口 更新 id = 2 的數據
1 mysql> begin; 2 Query OK, 0 rows affected (0.00 sec) 3 4 mysql> update t_user set username = 'b1' where id = 2; 5 Query OK, 1 row affected (0.00 sec) 6 Rows matched: 1 Changed: 1 Warnings: 0
在沒有提交的情況下,使用 C窗口 查看當前事務,我們可以看到事務的 狀態(trx_state)、行鎖數(trx_rows_locked)、修改數據行數(trx_rows_modified) 等信息
1 mysql> select * from innodb_trx\G; 2 *************************** 1. row *************************** 3 trx_id: A023 4 trx_state: RUNNING 5 trx_started: 2018-03-11 15:30:19 6 trx_requested_lock_id: NULL 7 trx_wait_started: NULL 8 trx_weight: 3 9 trx_mysql_thread_id: 5 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: 1 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
此時再使用 B窗口 刪除t_user表的數據,在刪除 id = 2 的數據時,發現事務被阻塞。我們在 C窗口 查看 processlist、事務以及鎖等待 情況
1 mysql> show full processlist;
1 mysql> select * from innodb_trx\G;
1 mysql> select * from INNODB_LOCK_WAITS\G;
當事務超時后出現1205的錯誤
此時,我們再查看一下 processlist、事務以及鎖等待 情況,發現剛才處於 等待狀態 的事務、process和鎖等待已經沒有了
1 mysql> show full processlist; 2 mysql> select * from INNODB_LOCK_WAITS\G; 3 mysql> select * from innodb_trx\G;
此時把 A窗口rollback 回來
mysql> rollback;
再查看一下processlist、事務以及鎖等待情況
由此可以確定:1205 的錯誤是因為未提交事務對數據加了行級鎖,當前事務獲取同一數據行級鎖超時導致的
三、解決方案
我們可以使用 show full processlist 查看未提交事務的連接的 id
可以看到這個連接的id是5
如果可以確定不是很重要的事務,我們可以使用kill命令斷開這個連接。
mysql> kill 5;
如果不確定的話,還是需要溝通一下如何安全處理。