【问题标题】:Understanding Deadlocks in MySQL了解 MySQL 中的死锁
【发布时间】:2019-11-22 09:52:49
【问题描述】:

我是 MySQL 新手,我曾经在 Oracle 数据库中工作。我在解决应用程序中的死锁时遇到了一些问题。请帮助我理解这个问题。 表定义:

CREATE TABLE `APPLICATION` (
  `ID` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `APPLICATION_NUMBER` varchar(35) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `STATUS` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `SUB_STATUS` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `SOURCE_TYPE` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `SOURCE_ID` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `SOURCE_CHANNEL` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `PRODUCT_PROGRAM` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `LOAN_TYPE` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `ASSIGNED_TO` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `CREATED_BY` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `CREATION_DATE` datetime DEFAULT NULL,
  `LAST_UPDATE_DT` datetime DEFAULT NULL,
  `LAST_UPDATE_BY` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `LOAN_AMOUNT` decimal(38,0) DEFAULT NULL,
  `INSURANCE_OPT_IN` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `RCU_STATUS` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `TVR_COMMENTS` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `TVR_DECISION` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `MM_PAID_TO` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `PURPOSE_OF_LOAN` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `MARGIN_MONEY` double DEFAULT NULL,
  `PAYMENT_MODE` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `IS_ELIGIBLE` decimal(1,0) DEFAULT NULL,
  `CRM_STATUS` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `CRM_REASON` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `IS_INTERESTED_CLI` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `IS_INTERESTED_CI` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `CRITICAL_ILLNESS` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `CREDIT_LIFE_INSURANCE` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `CREATE_USER` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `CREATE_DATE` datetime DEFAULT NULL,
  `LAST_UPDATE_USER` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `LAST_UPDATE_DATE` datetime DEFAULT NULL,
  `STATUS_ID` bigint(35) DEFAULT NULL,
  `SUBSTATUS_ID` bigint(35) DEFAULT NULL,
  `DOCUMEMNTUPLOAD_COMMENTS` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `DOCUMEMNTUPLOAD_ACK` decimal(1,0) DEFAULT NULL,
  `NO_OF_FINANCIERS_FOR_ALL_ASSET` decimal(3,0) DEFAULT NULL,
  `DUPLICATED_FROM` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`ID`) USING BTREE,
  UNIQUE KEY `UK_APPLICATION` (`APPLICATION_NUMBER`),
  KEY `FK_APL_STATID` (`STATUS_ID`) USING BTREE,
  KEY `FK_APL_SUBSTATID` (`SUBSTATUS_ID`) USING BTREE,
  CONSTRAINT `FK_APL_STATID` FOREIGN KEY (`STATUS_ID`) REFERENCES `STATUS` (`ID`) ON DELETE RESTRICT ON UPDATE RESTRICT,
  CONSTRAINT `FK_APL_SUBSTATID` FOREIGN KEY (`SUBSTATUS_ID`) REFERENCES `SUB_STATUS` (`ID`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

SHOW ENGINE INNODB STATUS 中的我的死锁详细信息:

------------------------
 LATEST DETECTED DEADLOCK
 ------------------------
 2019-11-22 04:48:06 0x2ad75cf91700
 *** (1) TRANSACTION:
 TRANSACTION 291327, ACTIVE 37 sec fetching rows
 mysql tables in use 1, locked 1
 LOCK WAIT 48 lock struct(s), heap size 8400, 1540 row lock(s), undo log entries 5
 MySQL thread id 14042, OS thread handle 47099630130944, query id 4174847 172.29.24.227 bpapi updating
 UPDATE APPLICATION SET NO_OF_FINANCIERS_FOR_ALL_ASSET = 7 WHERE id >'' AND APPLICATION_NUMBER = '001601'
 *** (1) WAITING FOR THIS LOCK TO BE GRANTED:
 RECORD LOCKS space id 3803 page no 21 n bits 144 index PRIMARY of table `BAPIDB`.`APPLICATION` trx id 291327 lock_mode X waiting
 Record lock, heap no 72 PHYSICAL RECORD: n_fields 42; compact format; info bits 128
  0: len 30; hex 65646466383861382d633733342d346561332d393665302d396366343234; asc eddf88a8-c734-4ea3-96e0-9cf424; (total 36 bytes);
  1: len 6; hex 000000046e42; asc     nB;;
  2: len 7; hex 02000000fa0518; asc        ;;
  3: len 6; hex 303031353930; asc 001590;;
  4: len 4; hex 31303033; asc 1003;;
  5: len 4; hex 31303033; asc 1003;;
  6: SQL NULL;
  7: SQL NULL;
  8: len 6; hex 506f7274616c; asc Portal;;
  9: SQL NULL;
  10: SQL NULL;
  11: SQL NULL;
  12: len 30; hex 35633131613436612d303963302d313165612d396533372d396165613961; asc 5c11a46a-09c0-11ea-9e37-9aea9a; (total 36 bytes);
  13: SQL NULL;
  14: len 5; hex 99a4ac4b92; asc    K ;;
  15: len 11; hex 427573696e657373415049; asc BusinessAPI;;
  16: SQL NULL;
  17: SQL NULL;
  18: SQL NULL;
  19: SQL NULL;
  20: SQL NULL;
  21: SQL NULL;
  22: SQL NULL;
  23: SQL NULL;
  24: SQL NULL;
  25: SQL NULL;
  26: len 7; hex 53554343455353; asc SUCCESS;;
  27: len 27; hex 5265636f72642055706461746564205375636365737366756c6c79; asc Record Updated Successfully;;
  28: SQL NULL;
  29: SQL NULL;
  30: SQL NULL;
  31: SQL NULL;
  32: SQL NULL;
  33: SQL NULL;
  34: SQL NULL;
  35: SQL NULL;
  36: SQL NULL;
  37: SQL NULL;
  38: SQL NULL;
  39: SQL NULL;
  40: SQL NULL;
  41: SQL NULL;

 *** (2) TRANSACTION:
 TRANSACTION 291891, ACTIVE 4 sec starting index read
 mysql tables in use 1, locked 1
 22 lock struct(s), heap size 1136, 10 row lock(s), undo log entries 8
 MySQL thread id 13972, OS thread handle 47104466163456, query id 4178089 172.29.25.88 bpapi updating
 UPDATE APPLICATION SET APPLICATION_NUMBER=IFNULL('001590', APPLICATION_NUMBER), STATUS=IFNULL('1003', STATUS), SUB_STATUS=IFNULL('1003', SUB_STATUS), CRM_STATUS=IFNULL('SUCCESS', CRM_STATUS), CRM_REASON=IFNULL('Record Created Successfully', CRM_REASON) WHERE ID='eddf88a8-c734-4ea3-96e0-9cf424ced71e'
 *** (2) HOLDS THE LOCK(S):
 RECORD LOCKS space id 3803 page no 21 n bits 144 index PRIMARY of table `BAPIDB`.`APPLICATION` trx id 291891 lock mode S locks rec but not gap
 Record lock, heap no 72 PHYSICAL RECORD: n_fields 42; compact format; info bits 128
  0: len 30; hex 65646466383861382d633733342d346561332d393665302d396366343234; asc eddf88a8-c734-4ea3-96e0-9cf424; (total 36 bytes);
  1: len 6; hex 000000046e42; asc     nB;;
  2: len 7; hex 02000000fa0518; asc        ;;
  3: len 6; hex 303031353930; asc 001590;;
  4: len 4; hex 31303033; asc 1003;;
  5: len 4; hex 31303033; asc 1003;;
  6: SQL NULL;
  7: SQL NULL;
  8: len 6; hex 506f7274616c; asc Portal;;
  9: SQL NULL;
  10: SQL NULL;
  11: SQL NULL;
  12: len 30; hex 35633131613436612d303963302d313165612d396533372d396165613961; asc 5c11a46a-09c0-11ea-9e37-9aea9a; (total 36 bytes);
  13: SQL NULL;
  14: len 5; hex 99a4ac4b92; asc    K ;;
  15: len 11; hex 427573696e657373415049; asc BusinessAPI;;
  16: SQL NULL;
  17: SQL NULL;
  18: SQL NULL;
  19: SQL NULL;
  20: SQL NULL;
  21: SQL NULL;
  22: SQL NULL;
  23: SQL NULL;
  24: SQL NULL;
  25: SQL NULL;
  26: len 7; hex 53554343455353; asc SUCCESS;;
  27: len 27; hex 5265636f72642055706461746564205375636365737366756c6c79; asc Record Updated Successfully;;
  28: SQL NULL;
  29: SQL NULL;
  30: SQL NULL;
  31: SQL NULL;
  32: SQL NULL;
  33: SQL NULL;
  34: SQL NULL;
  35: SQL NULL;
  36: SQL NULL;
  37: SQL NULL;
  38: SQL NULL;
  39: SQL NULL;
  40: SQL NULL;
  41: SQL NULL;

 *** (2) WAITING FOR THIS LOCK TO BE GRANTED:
 RECORD LOCKS space id 3803 page no 21 n bits 144 index PRIMARY of table `BAPIDB`.`APPLICATION` trx id 291891 lock_mode X locks rec but not gap waiting
 Record lock, heap no 72 PHYSICAL RECORD: n_fields 42; compact format; info bits 128
  0: len 30; hex 65646466383861382d633733342d346561332d393665302d396366343234; asc eddf88a8-c734-4ea3-96e0-9cf424; (total 36 bytes);
  1: len 6; hex 000000046e42; asc     nB;;
  2: len 7; hex 02000000fa0518; asc        ;;
  3: len 6; hex 303031353930; asc 001590;;
  4: len 4; hex 31303033; asc 1003;;
  5: len 4; hex 31303033; asc 1003;;
  6: SQL NULL;
  7: SQL NULL;
  8: len 6; hex 506f7274616c; asc Portal;;
  9: SQL NULL;
  10: SQL NULL;
  11: SQL NULL;
  12: len 30; hex 35633131613436612d303963302d313165612d396533372d396165613961; asc 5c11a46a-09c0-11ea-9e37-9aea9a; (total 36 bytes);
  13: SQL NULL;
  14: len 5; hex 99a4ac4b92; asc    K ;;
  15: len 11; hex 427573696e657373415049; asc BusinessAPI;;
  16: SQL NULL;
  17: SQL NULL;
  18: SQL NULL;
  19: SQL NULL;
  20: SQL NULL;
  21: SQL NULL;
  22: SQL NULL;
  23: SQL NULL;
  24: SQL NULL;
  25: SQL NULL;
  26: len 7; hex 53554343455353; asc SUCCESS;;
  27: len 27; hex 5265636f72642055706461746564205375636365737366756c6c79; asc Record Updated Successfully;;
  28: SQL NULL;
  29: SQL NULL;
  30: SQL NULL;
  31: SQL NULL;
  32: SQL NULL;
  33: SQL NULL;
  34: SQL NULL;
  35: SQL NULL;
  36: SQL NULL;
  37: SQL NULL;
  38: SQL NULL;
  39: SQL NULL;
  40: SQL NULL;
  41: SQL NULL;

 *** WE ROLL BACK TRANSACTION (2)

我的理解:

UPDATE APPLICATION
SET NO_OF_FINANCIERS_FOR_ALL_ASSET = 7
WHERE id >'' AND APPLICATION_NUMBER = '001601';

这个事务正在导致死锁,这是等待获取lock_mode X。

UPDATE APPLICATION
SET APPLICATION_NUMBER=IFNULL('001590', APPLICATION_NUMBER),
    STATUS=IFNULL('1003', STATUS),
    SUB_STATUS=IFNULL('1003', SUB_STATUS),
    CRM_STATUS=IFNULL('SUCCESS', CRM_STATUS),
    CRM_REASON=IFNULL('Record Created Successfully', CRM_REASON)
WHERE ID='eddf88a8-c734-4ea3-96e0-9cf424ced71e';

持有锁模式 S 并试图持有一个正在等待的 lock_mode X 第二次更新回滚。

我的问题是:

  1. 为什么第二次更新保持不变并且 lock_mode S ?不应该是 lock_mode X 就足够了吗?
  2. 这些更新了两个不同的行,我认为 lock_mode S 是罪魁祸首。我说的对吗?
  3. 如何避免这种死锁。

【问题讨论】:

  • 这是否正确:WHERE id >''?知道您正在使用哪个数据库引擎也很好。 InnoDB?
  • 是的,id 列是主键,否则它会给出安全更新的错误,在这篇文章之后添加了对 application_number 的唯一约束,请假设它不存在。我的数据库详细信息:MySQL:8.0.15,引擎:InnoDB,V. 10
  • 哎哟。这意味着您的第一次更新锁定了整个表...

标签: mysql deadlock database-deadlocks


【解决方案1】:
  1. 更新语句可能会在二级索引上设置共享锁,或者第二个事务中有其他语句在更新之前设置共享锁。正如mysql manual 所说:

在插入新二级索引记录之前执行重复检查扫描以及插入新二级索引记录时,UPDATE 操作也会对受影响的二级索引记录进行共享锁。

但是,在 InnoDB all secondary indexes also include the primary key 中,辅助键锁也会影响主键。但老实说,如果它只有一个独占锁,那不会改变结果。

  1. 不,你不正确。在第一个链接 mysql 手册中还说:

锁定读取、UPDATE 或 DELETE 通常会在 SQL 语句处理过程中扫描的每条索引记录上设置记录锁。语句中是否存在将排除该行的 WHERE 条件并不重要。 InnoDB 不记得确切的 WHERE 条件,而只知道扫描了哪些索引范围。

您在评论中写道,您在发布问题后application_number 列上添加了唯一索引。这意味着您的第一条 sql 语句会锁定整个表,因为 id >'' 匹配所有记录并且 application_number 字段没有被索引。

因此,不管您的第一个 sql 语句仅更新一条记录这一事实,您都设法锁定了整个表。这就引出了您的最后一个问题。

  1. 您不能也不能避免死锁:这是解决某些竞争条件的基本特征。您可以做两件事:

a) 处理死锁错误(重启事务、错误消息等)。 b) 尽量减少发生死锁的机会。

如何最大限度地减少发生死锁的机会?使用适当的索引和 where 条件来最小化被语句锁定的记录数;避免使用长时间运行的事务;尽量减少显式锁定的使用(更新、共享)。

您在application_number 上添加唯一索引是一个非常好的开始,但您必须使用explain 验证它是否被mysql 使用。

【讨论】:

  • 感谢 fotiosp 和 Shadow(记得我在 Oracle 论坛中提到的 Blue Shadow)。现在我明白了,在我发表这篇文章后,我添加了唯一索引,它有所帮助。现在,在负载测试期间不会出现这种特定的死锁。再次感谢,我真的很感激。
猜你喜欢
  • 2021-03-26
  • 1970-01-01
  • 1970-01-01
  • 2021-10-19
  • 2018-02-02
  • 2019-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多