Question

I suffer a strange mysql deadlock recently, my tables look like(for simplicity I deleted unrelevant columns):

CREATE TABLE Node (
    `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT,
    `nodeId` varchar(128) NOT NULL UNIQUE,
    PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE  JobQueue (
    `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT,
    `workerManagementNodeId` varchar(32) DEFAULT NULL,
    CONSTRAINT `fkJbqMgmtNodeId` FOREIGN KEY (`workerManagementNodeId`) REFERENCES `Node` (`nodeId`) ON DELETE SET NULL,
    PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

when my node goes down, it will delete record in Node table. At this point, job queue may be in process of deleting a queue in JobQueue table which has a foreign key to Node.nodeId. Then mysql throws out an exception:

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction

I checked the database, JobQueue was successfully deleted but Node wasn't. I understand order of foreign key may cause deadlock, but in my case Node table has no foreign key only primary key. Then how can the deadlock happen?

BTW: I am pretty sure the deadlock is caused by JobQueue, I spent much time narrowing down this problem so in my test only these two tables will be used.

UPDATE:

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;

I finally notice it's still an issue caused by foreign key order. there is actually another table JobQueueEntry which has both foreign key to Node and JobQueue in reversed order. so when deleting a node it's trying to update JobQueue and JobQueueEntry. the deadlock happens because JobQueueEntry has foreign key to JobQueue before node.

thanks @ctrl's answer!

Was it helpful?

Solution

First of all this should be a comment but I don't have enough rep for now, so... I base my "comment" on my Oracle experience, but I think it's a common issue and also mysql can behave in the same way.

Since you have a fk on delete set null, when you remove something from Node the db engine has to go thru JobQueue to update it, and it probably acquires a table lock to do this (oracle does it in your situation). If you have multiple actors, some updating/deleting Jobs table and some updating/deleting JobsQueue table, you can end up with a deadlock.

In Oracle, to fix this (and to get better performance) you usually create an index on the fk columns of the child table, in you case workerManagementNodeId.

In case mysql does this in a different and smarter way, I beg your pardon :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top