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存储引擎》