【Mysql】两条insert 语句产生的死锁

背景:查看status日志发现两条insert 出现了死锁
  1. ------------------------
  2. LATEST DETECTED DEADLOCK
  3. ------------------------
  4. 2017-10-24 12:53:56 7f8fbc165700
  5. *** (1) TRANSACTION:
  6. TRANSACTION 596252578, ACTIVE 0 sec inserting
  7. mysql tables in use 1, locked 1
  8. LOCK WAIT 14 lock struct(s), heap size 2936, 7 row lock(s), undo log entries 7
  9. MySQL thread id 17066316, OS thread handle 0x7f8eef3cf700, query id 2080508355 192.168.1.13 userservice update
  10. insert into
  11.         svc_order_service_item
  12.          ( work_order_id,
  13.         quantity    
  14.  )
  15.          values ( 2373314,1
  16. )
  17. *** (1) WAITING FOR THIS LOCK TO BE GRANTED:
  18. RECORD LOCKS space id 388 page no 27032 n bits 616 index `idx_svcorderserviceitem_workorderid_quantity` of table `ecejservice`.`svc_order_service_item` trx id 596252578 lock_mode X insert intention waiting
  19. Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
  20.  0: len 8; hex 73757072656d756d; asc supremum;;

  21. *** (2) TRANSACTION:
  22. TRANSACTION 596252580, ACTIVE 0 sec inserting
  23. mysql tables in use 1, locked 1
  24. 15 lock struct(s), heap size 2936, 7 row lock(s), undo log entries 8
  25. MySQL thread id 17061883, OS thread handle 0x7f8fbc165700, query id 2080508367 192.168.1.12 userservice update
  26. insert into
  27.         
  28.         svc_order_service_item
  29.     
  30.          ( work_order_id,
  31.         quantity,
  32.      )
  33.          values ( 2373315,
  34.         1
  35.     
  36.  )
  37. *** (2) HOLDS THE LOCK(S): --持有一个读锁
  38. RECORD LOCKS space id 388 page no 27032 n bits 616 index `idx_svcorderserviceitem_workorderid_quantity` of table `ecejservice`.`svc_order_service_item` trx id 596252580 lock_mode X
  39. Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
  40.  0: len 8; hex 73757072656d756d; asc supremum;;

  41. *** (2) WAITING FOR THIS LOCK TO BE GRANTED:
  42. RECORD LOCKS space id 388 page no 27032 n bits 616 index `idx_svcorderserviceitem_workorderid_quantity` of table `ecejservice`.`svc_order_service_item` trx id 596252580 lock_mode X insert intention waiting
  43. Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
  44.  0: len 8; hex 73757072656d756d; asc supremum;;

  45. *** WE ROLL BACK TRANSACTION (1)
  46. ------------
注意: 在innodb 日志中如果提示 lock mode S /lock mode X ,其实都是gap锁,如果是行记录锁 会提示but not gap ,请读者朋友们在自己分析死锁日志的时候注意。

分析:

1.表上有聚集索引和二级索引,死锁发生在二级索引idx_svcorderserviceitem_workorderid_quantity上

2.
  1. RECORD LOCKS space id 388 page no 27032 n bits 616 index `idx_svcorderserviceitem_workorderid_quantity` of table `ecejservice`.`svc_order_service_item` trx id 596252578 lock_mode X insert intention waiting
可以确定,这个x锁不是由于INSERT产生的,因为 INSERT可能产生的锁包括检查dup key时的s锁,隐式锁转换为显式锁(not gap,要在二级索引上产生lock_mode为X的LOCK_ORDINARY类型的锁(包括记录及记录前面的gap),据我所知一般是根据二级索引扫描进行记录更新导致的。

3. 根据
LOCK WAIT 14 lock struct(s), heap size 2936, 7 row lock(s), undo log entries 7
有7个undo entires,而单纯的INSERT一条记录只有一个undo entry,因此可以推断除了INSERT,必然还有别的操作

基于以上,事务除了INSERT,可能还存在DELETE/UPDATE,并且这些操作是走的二级索引来查找更新记录。

一个简单但不完全相同的重现步骤:
DROP TABLE t1;
CREATE TABLE `t1` (
  `a` int(11) NOT NULL AUTO_INCREMENT,
  `b` int(11) DEFAULT NULL,
  `c` int(11) DEFAULT NULL,
  PRIMARY KEY (`a`),
  KEY `b` (`b`)
) ENGINE=InnoDB ;
insert into t1(a, b,c) values(1,2,3),(5,4,6),(8, 7,9),(12,12,19),(15,15,11);

session1:

begin;
delete from t1 where b = 12;
//二级索引上lock_mode X、lock_mode X locks gap before rec以及主键上的lock_mode X locks rec but not gap
二级索引:heap_no=5, type_mode=3  (12上的LOCK_ORDINARY类型锁,包括记录和记录前的GAP)
聚集索引:heap_no=5,type_mode=1027
二级索引:heap_no=6,type_mode=547(15上的GAP锁)
session2:
begin;
delete from t1 where b = 7;
//二级索引上lock_mode X、lock_mode X locks gap before rec以及主键上的lock_mode X locks rec but not gap
二级索引:heap_no=4,type_mode=3       (7上的LOCK_ORDINARY类型锁,包括记录和记录前的GAP)
聚集索引:heap_no=4,type_mode=1027
二级索引:heap_no=5,type_mode=547    (记录12上的GAP锁)
session1:
insert into t1 values (NULL, 6,10);
//新插入记录聚集索引无冲突插入成功,二级索引等待插入意向锁(lock_mode X locks gap before rec insert intention waiting)
二级索引,heap_no=4, type_mode=2819 (请求记录7上面的插入意向锁 LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION, 需要等待session2
session2:
insert into t1 values (NULL, 7,10);
二级索引:heap_no=5,  type_mode=2819  (请求记录12上的插入意向锁 LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION,需要等待session1)
互相等待,导致发生死锁
从打印的死锁信息来看,基本和线上发生的死锁现象是一致的。


再举一个例子
mysql> select * from test01;
+----+-----+
| id | app |
+----+-----+
| 1 | 01 |
| 2 | 02 |
| 5 | 03 |
| 10 | 03 |
| 6 | 04 |
| 7 | 05 |
| 8 | 06 |
| 9 | 06 |
| 11 | 06 |
| 12 | 07 |
| 13 | 08 |
| 14 | 09 |
| 15 | 09 |
+----+-----+
13 rows in set (0.00 sec)

session1: mysql> select now();start TRANSACTION;      
+---------------------
| now() |
+---------------------+
| 2018-01-25 16:08:46 |
+---------------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

mysql> select * from test01 where app='05' for update; ---第1步 锁住【6.04】-【7.05】以及【7.05】-【8.06】 两段区间
+----+-----+
| id | app |
+----+-----+
| 7 | 05 |
+----+-----+
1 row in set (0.00 sec)

mysql> insert into test01(app) values ('07');           --第三步 等待第二步释放
Query OK, 1 row affected (23.24 sec)



session2:
mysql> select * from test01 where app='08' for update;  --第二步 锁住【12,07】-【13,08】以及【13,08】-【14,09】两段区间
+----+-----+
| id | app |
+----+-----+
| 13 | 08 |
+----+-----+
1 row in set (0.00 sec)

mysql> insert into test01(app) values ('04');                  ----第四步 等待第一步释放,,于是死锁
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction


查看死锁日志:
LATEST DETECTED DEADLOCK
------------------------
2018-01-25 16:09:54 0x7f07d23ff700
*** (1) TRANSACTION:
TRANSACTION 5375, ACTIVE 51 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 5 lock struct(s), heap size 1136, 4 row lock(s), undo log entries 1
MySQL thread id 2294, OS thread handle 139671567841024, query id 42463 localhost root update
insert into test01(app) values ('07')
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 64 page no 4 n bits 80 index idx_app of table `devops`.`test01` trx id 5375 lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 12 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 2; hex 3038; asc 08;;
 1: len 4; hex 0000000d; asc ;;

*** (2) TRANSACTION:
TRANSACTION 5376, ACTIVE 38 sec inserting
mysql tables in use 1, locked 1
5 lock struct(s), heap size 1136, 4 row lock(s), undo log entries 1
MySQL thread id 2293, OS thread handle 139671568905984, query id 42464 localhost root update
insert into test01(app) values ('04')

*** (2) HOLDS THE LOCK(S): RECORD LOCKS space id 64 page no 4 n bits 80 index idx_app of table `devops`.`test01` trx id 5376 lock_mode X
Record lock, heap no 12 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 2; hex 3038; asc 08;;
 1: len 4; hex 0000000d; asc ;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 64 page no 4 n bits 80 index idx_app of table `devops`.`test01` trx id 5376 lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 6 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 2; hex 3035; asc 05;;
 1: len 4; hex 00000007; asc ;;

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

死锁日志是不是和上面的一样?



参考:
http://blog.itpub.net/22664653/viewspace-2145068/    ----杨奇龙 
http://www.sohu.com/a/169663059_610509   ---insert ..select 语句产生死锁
http://blog.itpub.net/7728585/viewspace-2146183/   ---insert ..select 语句产生死锁 --八怪

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/29096438/viewspace-2146310/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/29096438/viewspace-2146310/

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MySQL中,死锁是指两个或多个事务相互等待对方释放资源的情况,导致事务无法继续执行并被数据库系统检测到。当发生死锁时,MySQL会选择其中一个事务进行回滚,以解开死锁并允许其他事务继续执行。 要解决MySQL中的插入死锁问题,可以考虑以下几点: 1. 使用合理的事务隔离级别:MySQL提供了多个事务隔离级别,如读未提交、读已提交、可重复读和串行化。根据业务需求和并发情况,选择合适的隔离级别可以减少死锁的可能性。 2. 优化事务的执行顺序:在编写代码时,尽量避免多个事务同时对相同的资源进行操作。如果必须同时操作相同的资源,可以通过调整事务的执行顺序来减少死锁的风险。 3. 减少事务的持有时间:长时间持有锁资源是产生死锁的常见原因之一。尽量缩短事务的执行时间,避免长时间占用锁资源,从而减少死锁的可能性。 4. 使用索引和合适的查询语句:良好的索引设计和合适的查询语句可以提高查询效率,减少锁冲突的可能性。确保表中的字段有适当的索引,并编写高效的查询语句。 5. 监控和处理死锁MySQL提供了一些系统变量和工具来监控和处理死锁。可以通过设置合适的参数来记录死锁日志,并及时处理死锁情况,以便快速恢复正常的数据库操作。 请注意,以上仅是一些常见的解决方案,具体的解决方法还需根据具体的业务场景和数据库设计进行调整和优化。在实际应用中,可能需要综合考虑多个因素来解决死锁问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值