Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
主键会导致mysql死锁吗?_Mysql_Sql_Deadlock - Fatal编程技术网

主键会导致mysql死锁吗?

主键会导致mysql死锁吗?,mysql,sql,deadlock,Mysql,Sql,Deadlock,我最近遇到了一个奇怪的mysql死锁,我的表看起来像(为了简单起见,我删除了不相关的列): 当我的节点关闭时,它将删除节点表中的记录。此时,作业队列可能正在删除作业队列表中具有Node.nodeId外键的队列。然后mysql抛出一个异常: 原因:com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException:尝试获取锁时发现死锁;尝试重新启动事务 我检查了数据库,JobQueue已成功删除,但节点未删除。我知道外键的顺序可能会导

我最近遇到了一个奇怪的mysql死锁,我的表看起来像(为了简单起见,我删除了不相关的列):

当我的节点关闭时,它将删除节点表中的记录。此时,作业队列可能正在删除作业队列表中具有Node.nodeId外键的队列。然后mysql抛出一个异常:

原因:com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException:尝试获取锁时发现死锁;尝试重新启动事务

我检查了数据库,JobQueue已成功删除,但节点未删除。我知道外键的顺序可能会导致死锁,但在我的例子中,节点表并没有外键,只有主键。那么僵局怎么会发生呢

顺便说一句:我很确定死锁是由JobQueue引起的,我花了很多时间来缩小这个问题,所以在我的测试中只会使用这两个表

更新:

CREATE TABLE  JobQueueEntry (
    `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT,
    `name` varchar(255) NOT NULL,
    `jobQueueId` bigint unsigned NOT NULL,
    `issuerManagementNodeId` varchar(32) DEFAULT NULL,
    PRIMARY KEY  (`id`),
    CONSTRAINT `fkJbqEtryMgmtNodeId` FOREIGN KEY (`issuerManagementNodeId`) REFERENCES `Node` (`nodeId`) ON DELETE SET NULL,
    CONSTRAINT `fkJobQueueId` FOREIGN KEY (`jobQueueId`) REFERENCES `JobQueue` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
我终于注意到它仍然是由外键顺序引起的问题。实际上还有另一个表JobQueueEntry,它以相反的顺序同时具有指向节点和JobQueue的外键。因此,删除节点时,它会尝试更新JobQueue和JobQueueEntry。发生死锁的原因是JobQueueEntry在节点之前具有JobQueue的外键


谢谢@ctrl的回答

首先,这应该是一个评论,但我现在没有足够的代表,所以。。。我的“评论”基于我的Oracle经验,但我认为这是一个常见的问题,mysql也可以以同样的方式运行

由于您有一个fk on delete集合null,当您从节点中删除某些内容时,db引擎必须通过JobQueue对其进行更新,并且它可能会获取一个表锁来执行此操作(oracle在您的情况下会这样做)。如果您有多个参与者,一些更新/删除作业表和一些更新/删除作业表,则可能会导致死锁

在Oracle中,为了解决这个问题(并获得更好的性能),通常需要在子表的fk列上创建一个索引,例如workerManagementNodeId


如果mysql以另一种更智能的方式实现这一点,请原谅:)

当您的系统处于负载状态时,请查看
SHOW PROCESSLIST
。您可能会看到许多积压的查询。@tadman SHOw PROCESSLIST似乎正常,连接数与连接池大小匹配。积压查询是什么意思?在高负载下,MySQL有时会以“死锁”类型的消息导致查询失败,因为它无法获得表上的锁来插入或更新数据。这只是一个猜测,因为您的模式似乎足够简单。不过,更新索引可能是一项代价高昂的操作,因此在发生这种情况时,最好密切监视服务器的行为,以便更好地了解发生这种情况的条件。你能可靠地复制它吗?@tadman是的,系统负载很重,我启动1000个线程并行执行作业是的,我的测试放置了一个重节点,其中1000个线程并行执行作业。在Job表上有很多更新,Job表也有JobQueue表的外键。但索引如何解决这个问题呢?这仅仅是为了提高性能以减少死锁发生的可能性吗?它不仅仅是一个性能修复,它实际上改变了子表的锁定方式(行锁而不是全表锁)并防止死锁。你可以在这里找到一个解释。
CREATE TABLE  JobQueueEntry (
    `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT,
    `name` varchar(255) NOT NULL,
    `jobQueueId` bigint unsigned NOT NULL,
    `issuerManagementNodeId` varchar(32) DEFAULT NULL,
    PRIMARY KEY  (`id`),
    CONSTRAINT `fkJbqEtryMgmtNodeId` FOREIGN KEY (`issuerManagementNodeId`) REFERENCES `Node` (`nodeId`) ON DELETE SET NULL,
    CONSTRAINT `fkJobQueueId` FOREIGN KEY (`jobQueueId`) REFERENCES `JobQueue` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;