我有一个表来存储从多个进程访问的SQS队列的状态。它现在的工作方式是将队列中的所有消息添加到表中。每次将队列中的消息出队时,也会将其从表中删除。当表/队列为空时,需要运行一些finalization操作。它目前的实现方式是:
-- dequeue (2 statements so that we can use the primary index for the delete - was seeing a lot of deadlocking otherwise)
BEGIN;
SELECT id FROM messages WHERE messageKey = 'message_key' LIMIT 1 FOR UPDATE;
DELETE FROM messages WHERE id = 'auto_inc_id';
COMMIT;
-- check if it was the last one (shared lock so we know that nobody is currently deleting a message - select count(*) was also causing deadlocks due to locking so many rows)
SELECT * FROM messages LIMIT 1 LOCK IN SHARE MODE;
-- perform finalization if no records returned不幸的是,这些语句似乎彼此引起了一些争用,这导致了应用程序的缓慢-有没有一种明显的方法可以做到这一点,它仍然是原子的,但需要更少的语句或事务?
该表非常简单,但如果有人感兴趣,我将把它包括在内
CREATE TABLE IF NOT EXISTS `messages` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`messageKey` VARCHAR(256) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;发布于 2020-12-09 12:00:21
BEGIN;
SELECT @id := id FROM ... FOR UPDATE;
IF (@id IS NOT NULL) THEN
DELETE ... WHERE id = @id;
END IF;
COMMIT;然后继续使用@id。
逻辑上有一个缺陷:如果服务器在您使用@id完成之前崩溃,则无法恢复。
如果你想讨论修复这个缺陷,首先回答这个问题:如果你“使用”@id两次,会造成伤害吗?
https://stackoverflow.com/questions/65205058
复制相似问题