MySQL死鎖簡單案例演示
阿新 • • 發佈:2018-11-15
MySQL死鎖簡單案例演示【存在疑問】
請各位讀者對本篇文章採取疑問的態度。
1.環境
- mysql 5.7
- windows
2.示例1
mysql> CREATE TABLE t (i INT) ENGINE = InnoDB;
Query OK, 0 rows affected (0.26 sec)
- Client A起事務,以share 鎖模式讀取資料
mysql> start transaction;
Query OK, 0 rows affected (0.03 sec)
mysql> SELECT * FROM t WHERE i = 1 lock in SHARE mode;
+------+
| i |
+------+
| 1 |
+------+
1 row in set (0.00 sec)
- Client B另起事務,刪除表t中的資料
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> delete from t;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
上面的這個超時錯將會在命令執行一段時間之後,才出現。其超時時間預設設定為50s:
mysql> show variables like 'innodb_lock_wait_timeout';
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| innodb_lock_wait_timeout | 50 |
+--------------------------+-------+
1 row in set, 1 warning (0.03 sec)
在這個出錯命令尚未出現之前,在Client A中繼續執行如下命令:
mysql> DELETE FROM t WHERE i = 1;
Query OK, 1 row affected (0.00 sec)
結果在Client B中出現的結果如下:
mysql> DELETE FROM t WHERE i = 1;
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
3.示例2【外來鍵約束至死鎖】
- 建表語句
CREATE TABLE `parent` (
`id` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
CREATE TABLE `child` (
`id` int(11) DEFAULT NULL,
KEY `id_for` (`id`),
CONSTRAINT `id_for` FOREIGN KEY (`id`) REFERENCES `parent` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
- 執行SQL
在session A執行如下命令:
mysql> begin;
Query OK, 0 rows affected (0.03 sec)
mysql> delete from parent where id = 3;
Query OK, 1 row affected (0.01 sec)
在session B執行如下命令:
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into child select 3;
發現Session B的回話一直呈阻塞態。
檢視information_schema.innodb_locks
表資料,如下:
mysql> select * from information_schema.innodb_locks\G
*************************** 1. row ***************************
lock_id: 21305:145:3:4
lock_trx_id: 21305
lock_mode: S
lock_type: RECORD
lock_table: `insidemysql`.`parent`
lock_index: PRIMARY
lock_space: 145
lock_page: 3
lock_rec: 4
lock_data: 3
*************************** 2. row ***************************
lock_id: 21303:145:3:4
lock_trx_id: 21303
lock_mode: X
lock_type: RECORD
lock_table: `insidemysql`.`parent`
lock_index: PRIMARY
lock_space: 145
lock_page: 3
lock_rec: 4
lock_data: 3
2 rows in set, 1 warning (0.01 sec)
發現出現死鎖。
死鎖過程很簡單:Session A首先發起一個事務(以begin起),接著欲刪除parent表中id=3的行記錄。這個操作會發起鎖操作,申請一個x鎖【如上述SQL所示,lock_trx_id為21303,其lock_mode為x型】。然後另外的一個回話Session B發起一個事務(begin起),欲插入一條id=3的記錄【如上述SQL所示,lock_trx_id為21305,其lock_mode為s型】。但是因為parent表中的id是child表中的id的外來鍵,所以導致阻塞的產生。注意它們的lock_id 以及lock_data均相同,表明鎖住的行記錄相同。
4. 參考文章
-
1.https://dev.mysql.com/doc/refman/5.7/en/innodb-deadlock-example.html
我對本文是有疑問的,因為在Client A中是可以直接刪除資料的,而不是Client A陷入了死鎖。參考文獻對於這個問題可能產生死鎖的解釋是:- Client A 獲得一個s鎖(並一直持有【用事務保持狀態】)
- Client B請求獲得一個x鎖(刪除某行資料)
- Client A接著請求一個x鎖(也想刪除該行資料)
- 於是Client A,B均陷入死鎖
-
2.《Mysql技術內幕:InnoDB儲存引擎》