为什么这会触发锁定?

时间:2012-05-26 04:38:55

标签: mysql triggers repeat

我使用下面显示的触发器自动为插入的行分配随机密钥,如果找到现有行,则重试随机生成。 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

1 个答案:

答案 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