欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

MySQL 待解决死锁

程序员文章站 2022-04-17 14:38:35
...

官方文档:https://dev.mysql.com/doc/refman/5.6/en/innodb-locks-set.html

线上出现一个死锁现象,信息显示的是两条对同一个表的不同记录的update操作,表上只有一个主键索引,更新的条件上无索引,时间地段显示两个update只相差1ms

业务场景是同时一个事务中先是insert 再update新插入的行,存在并发;数据库环境是5.6,事务隔离级别RC,auto_increment_increment=1

通过定时任务实现两个会话同时对一个表先进行insert,然后update

#表结构
mysql> show create table test.t3;
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                                                                  |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| t3    | CREATE TABLE `t3` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) DEFAULT NULL,
  `col` varchar(10) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=225 DEFAULT CHARSET=utf8 |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
#定时任务
32 13 * * * for i in `seq 100`;do /usr/local/mysql/bin/mysql -uroot -S /tmp/mysql_3309.sock -e "begin;insert into test.t3 values(null,'aa','$i');update test.t3 set name='aa$i' where col='$i';commit;";done
32 13 * * * for i in `seq 100 200`;do /usr/local/mysql/bin/mysql -uroot  -S /tmp/mysql_3309.sock -e "begin;insert into test.t3 values(null,'aa','$i');update test.t3 set name='aa$i' where col='$i';commit;";done

捕获到的死锁信息

------------------------
LATEST DETECTED DEADLOCK
------------------------
2017-06-08 13:32:04 0x7f5277ba6700
*** (1) TRANSACTION:
TRANSACTION 696509, ACTIVE 0 sec fetching rows
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 2
MySQL thread id 112, OS thread handle 139992172484352, query id 965 localhost root updating
update test.t3 set name='aa26' where col='26'
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 83 page no 3 n bits 152 index PRIMARY of table `test`.`t3` trx id 696509 lock_mode X locks rec but not gap waiting
Record lock, heap no 82 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 4; hex 8000004c; asc    L;;
 1: len 6; hex 0000000aa0be; asc       ;;
 2: len 7; hex b6000001910110; asc        ;;
 3: len 2; hex 6161; asc aa;;
 4: len 3; hex 313236; asc 126;;

*** (2) TRANSACTION:
TRANSACTION 696510, ACTIVE 0 sec fetching rows
mysql tables in use 1, locked 1
3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
MySQL thread id 113, OS thread handle 139992172750592, query id 966 localhost root updating
update test.t3 set name='aa126' where col='126'
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 83 page no 3 n bits 152 index PRIMARY of table `test`.`t3` trx id 696510 lock_mode X locks rec but not gap
Record lock, heap no 82 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 4; hex 8000004c; asc    L;;
 1: len 6; hex 0000000aa0be; asc       ;;
 2: len 7; hex b6000001910110; asc        ;;
 3: len 2; hex 6161; asc aa;;
 4: len 3; hex 313236; asc 126;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 83 page no 3 n bits 152 index PRIMARY of table `test`.`t3` trx id 696510 lock_mode X locks rec but not gap waiting
Record lock, heap no 83 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 4; hex 8000004b; asc    K;;
 1: len 6; hex 0000000aa0bd; asc       ;;
 2: len 7; hex 3500000142133d; asc 5   B =;;
 3: len 4; hex 61613236; asc aa26;;
 4: len 2; hex 3236; asc 26;;

*** WE ROLL BACK TRANSACTION (2)
------------

解决

mysql> explain update test.t3 set name='aa126' where col='126'
    -> ;
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
|  1 | UPDATE      | t3    | NULL       | index | NULL          | PRIMARY | 4       | NULL |  382 |   100.00 | Using where |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
1 row in set (0.00 sec)

更新操作会对主键索引进行全索引扫描,我的理解为会一行行的处理先在innodb层在主键上加X锁,然后再server层通过where条件进行过滤,释放不符合条件的记录上的锁

在where条件字段上加索引,避免全索引扫描

测试发现通过在where条件上添加索引可以解决问题,但是还是无法解释这一现象,因为单独将事务拿出来重现是不会产生阻塞的,只有高并发下才会产生。。。。有知道的朋友请留言。