[关闭]
@Wahson 2018-10-10T11:38:17.000000Z 字数 3164 阅读 671

2018-09-19线上采购死锁

Today 总结 死锁


  1. 2018-09-19T19:53:58.315961+08:00 2461767 [Note] InnoDB: Transactions deadlock detected, dumping detailed information.
  2. 2018-09-19T19:53:58.315987+08:00 2461767 [Note] InnoDB:
  3. *** (1) TRANSACTION:
  4. TRANSACTION 494216479, ACTIVE 0 sec inserting
  5. mysql tables in use 1, locked 1
  6. LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
  7. MySQL thread id 2461759, OS thread handle 140237770991360, query id 2826738242 192.168.20.133 today_user update
  8. INSERT INTO code_gen_info SET
  9. prefix = '3811700403',
  10. `date` = '2018-09-19 19:53:58.315',
  11. code_length = 4,
  12. max_code = 2
  13. ON DUPLICATE KEY UPDATE max_code = 2
  14. 2018-09-19T19:53:58.316042+08:00 2461767 [Note] InnoDB: *** (1) WAITING FOR THIS LOCK TO BE GRANTED:
  15. RECORD LOCKS space id 1139 page no 293 n bits 632 index uniq_pre_date of table `purchase_db`.`code_gen_info` trx id 494216479 lock_mode X locks gap before rec insert intention waiting
  16. Record lock, heap no 183 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
  17. 0: len 10; hex 33383131373030353032; asc 3811700502;;
  18. 1: len 3; hex 8fc524; asc $;;
  19. 2: len 8; hex 000000000001318f; asc 1 ;;
  20. 2018-09-19T19:53:58.316177+08:00 2461767 [Note] InnoDB: *** (2) TRANSACTION:
  21. TRANSACTION 494216480, ACTIVE 0 sec inserting, thread declared inside InnoDB 5000
  22. mysql tables in use 1, locked 1
  23. 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
  24. MySQL thread id 2461767, OS thread handle 140237737445120, query id 2826738243 192.168.20.102 today_user update
  25. INSERT INTO code_gen_info SET
  26. prefix = '3811700403',
  27. `date` = '2018-09-19 19:53:58.315',
  28. code_length = 4,
  29. max_code = 2
  30. ON DUPLICATE KEY UPDATE max_code = 2
  31. 2018-09-19T19:53:58.316205+08:00 2461767 [Note] InnoDB: *** (2) HOLDS THE LOCK(S):
  32. RECORD LOCKS space id 1139 page no 293 n bits 632 index uniq_pre_date of table `purchase_db`.`code_gen_info` trx id 494216480 lock_mode X locks gap before rec
  33. Record lock, heap no 183 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
  34. 0: len 10; hex 33383131373030353032; asc 3811700502;;
  35. 1: len 3; hex 8fc524; asc $;;
  36. 2: len 8; hex 000000000001318f; asc 1 ;;
  37. 2018-09-19T19:53:58.316335+08:00 2461767 [Note] InnoDB: *** (2) WAITING FOR THIS LOCK TO BE GRANTED:
  38. RECORD LOCKS space id 1139 page no 293 n bits 632 index uniq_pre_date of table `purchase_db`.`code_gen_info` trx id 494216480 lock_mode X locks gap before rec insert intention waiting
  39. Record lock, heap no 183 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
  40. 0: len 10; hex 33383131373030353032; asc 3811700502;;
  41. 1: len 3; hex 8fc524; asc $;;
  42. 2: len 8; hex 000000000001318f; asc 1 ;;
  43. 2018-09-19T19:53:58.316459+08:00 2461767 [Note] InnoDB: *** WE ROLL BACK TRANSACTION (2)

表结构:

  1. CREATE TABLE `code_gen_info` (
  2. `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
  3. `prefix` varchar(10) NOT NULL DEFAULT '' COMMENT '前缀, 如32, 3511712000',
  4. `date` date DEFAULT NULL COMMENT '日期',
  5. `max_code` int(11) NOT NULL DEFAULT '1' COMMENT '当前最大编码值',
  6. `code_length` int(11) NOT NULL DEFAULT '4' COMMENT '递增编码长度',
  7. `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  8. PRIMARY KEY (`id`),
  9. UNIQUE KEY `uniq_pre_date` (`prefix`,`date`)
  10. ) ENGINE=InnoDB AUTO_INCREMENT=388033 DEFAULT CHARSET=utf8mb4 COMMENT='编码生成信息表'

日志分析:


  1. 说明:上述两个事务发生在不同节点的服务器上,线程1 线程2 几乎在同一个时间查询code_gen_info 的记录,并希望通过select for update的方式把查询到的记录锁住。首先,select for update where条件能匹配出记录的情况下,会把该记录锁住(X Lock),然而,在案发的时刻,数据库中没有符合条件的记录。此时,两个事务在select for update 时仅仅拿到了gap锁。
  2. 关键点是: gap锁之间是兼容的,也就是说,两个线程都愉快地以为拿到了排它锁,并继续往后执行insert语句。
  3. 双方在执行insert 语句时,都需要都申请插入意向锁,然鹅插入意向锁与gap锁是不兼容的锁,导致两个事务都在等待对方释放gap锁。从而死锁产生。
  4. 备注:
  5. MySQL 5.7.14
  6. RR隔离级别
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注