查看系统环境
#查看死锁参数 show variables like '%deadlock%'; #开启记录死锁 set global innodb_print_all_deadlocks=1; #查看隔离级别 SHOW VARIABLES LIKE '%isolation%'; #查看是否自动提交 SHOW VARIABLES LIKE '%auto%'; 环境为RR隔离级别,默认自动提交,语句显示开启事务
创建测试表并插入测试数据
#创建测试表并插入测试数据 use test; CREATE TABLE `test` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `a` int(11) unsigned DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `a` (`a`) ) ENGINE=InnoDB AUTO_INCREMENT=100 DEFAULT CHARSET=utf8; insert into `test` values(1,1),(2,2),(4,4);
在对应的连接中执行下面语句
#连接1 begin; delete from test where a = 2; #连接2 begin; delete from test where a = 2; #连接1 insert into test (id, a) values (10, 2);
此时在错误日志中可以看到下面的信息
2017-02-24 17:45:54 1fbcInnoDB: transactions deadlock detected, dumping detailed information. 2017-02-24 17:45:54 1fbc *** (1) TRANSACTION: TRANSACTION 3445, ACTIVE 9 sec starting index read mysql tables in use 1, locked 1 LOCK WAIT 2 lock struct(s), heap size 312, 1 row lock(s) MySQL thread id 16, OS thread handle 0x1e04, query id 261 localhost 127.0.0.1 root updating delete from test where a = 2 *** (1) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 12 page no 4 n bits 72 index `a` of table `test`.`test` trx id 3445 lock_mode X waiting Record lock, heap no 3 PHYSICAL RECORD: n_fields 2; compact format; info bits 32 0: len 4; hex 00000002; asc ;; 1: len 4; hex 00000002; asc ;; *** (2) TRANSACTION: TRANSACTION 3444, ACTIVE 12 sec inserting mysql tables in use 1, locked 1 4 lock struct(s), heap size 312, 3 row lock(s), undo log entries 2 MySQL thread id 15, OS thread handle 0x1fbc, query id 262 localhost 127.0.0.1 root update insert into test (id, a) values (10, 2) *** (2) HOLDS THE LOCK(S): RECORD LOCKS space id 12 page no 4 n bits 72 index `a` of table `test`.`test` trx id 3444 lock_mode X locks rec but not gap Record lock, heap no 3 PHYSICAL RECORD: n_fields 2; compact format; info bits 32 0: len 4; hex 00000002; asc ;; 1: len 4; hex 00000002; asc ;; *** (2) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 12 page no 4 n bits 72 index `a` of table `test`.`test` trx id 3444 lock mode S waiting Record lock, heap no 3 PHYSICAL RECORD: n_fields 2; compact format; info bits 32 0: len 4; hex 00000002; asc ;; 1: len 4; hex 00000002; asc ;; *** WE ROLL BACK TRANSACTION (1)
分析
步骤 | 连接1 | 连接2 |
1 | begin; | |
2 | delete from test where a = 2; 执行成功,连接1占有a=2下的X锁,类型为记录锁。 | |
3 | begin; | |
4 | delete from test where a = 2; 连接2希望申请a=2下的X锁,但是由于连接1已经申请了一把X锁,两把X锁互斥,所以X锁申请进入锁请求队列。 | |
5 | insert into test (id, a) values (10, 2); 由于a字段建立了唯一索引,所以需要申请S锁以便检查duplicate key,由于插入的a的值还是2,所以排在X锁后面。但是前面的X锁的申请只有在连接1commit或者rollback之后才能成功,此时形成了循环等待,死锁产生。 | 出现死锁,连接2权重较小,所以被选择回滚(成为牺牲品)。 |