我使用下面显示的触发器自动为插入的行分配随机密钥,如果找到现有行,则重试随机生成。 99.9%的时间完全符合预期。但是,每隔几周左右触发器锁定,其中的REPEAT
循环显然变得无限;查询无限期地继续,有效地锁定应用程序,并且必须KILL
编辑。
据我所知,所涉及的逻辑并没有让它看起来好像应该发生。涉及的关键空间肯定无法用尽,永远不会。发生了什么事?
触发器:
DELIMITER //;
CREATE TRIGGER `mytable_insert` BEFORE INSERT ON `mytable`
FOR EACH ROW
BEGIN
DECLARE `curr` BIGINT UNSIGNED;
DECLARE `sel` BIGINT UNSIGNED;
IF NEW.`mykey` IS NULL THEN
REPEAT
SELECT FLOOR(RAND() * 18446744073709551615) INTO `sel`;
SELECT `id` INTO `curr` FROM `mytable` WHERE `mykey` = `sel` LIMIT 1;
UNTIL `curr` IS NULL END REPEAT;
SET NEW.`mykey` = `sel`;
END IF;
END
答案 0 :(得分:2)
错误就是这一行
SELECT `id` INTO `curr` FROM `mytable` WHERE `mykey` = `sel` LIMIT 1;
如果没有行符合mykey = sel
,则根本不会分配curr。
因此,如果它被分配了任何其他东西,那么curr永远不会为空。
替换为此类内容(未经测试)
DELIMITER //;
CREATE TRIGGER `mytable_insert` BEFORE INSERT ON `mytable`
FOR EACH ROW
BEGIN
DECLARE `count` INT UNSIGNED;
DECLARE `sel` BIGINT UNSIGNED;
IF NEW.`mykey` IS NULL THEN
REPEAT
SELECT FLOOR(RAND() * 18446744073709551615) INTO `sel`;
SELECT count(1) INTO `count` FROM `mytable` WHERE `mykey` = `sel`;
UNTIL `count` = 0 END REPEAT;
SET NEW.`mykey` = `sel`;
END IF;
END