基于 AUTO_INCREMENT 字段的触发器在多行 INSERT 上工作不正确

问题描述

我使用 MysqL 5.6 和 item 表 (InnoDB),如下所示。

姓名 类型
item_id int(11)
item_code varchar(20)
名称 varchar(100)
cat_type varchar(50)
prod_grp varchar(12)
股票 int(11)
价格 双重
添加日期 时间戳

item_id 列是一个 AUTO_INCREMENT 字段。

还有另外两个表,分别称为 productscategoryproducts 表有 prod_grpprod_code 列。 category 表有 cat_typecat_code 列。

item_code 表的

item 是通过连接 item_id、{{1} } 和 cat_code 表。

我为 prod_code 表定义了一个触发器,它可以在 item 表中有 category自动更新 products

item

当我进行如下插入时,触发器会正常工作并按预期更新 item_code。

item_code

比如说,如果最后一个 INSERT 是 723,那么 item 被更新为“MM-hm-hk-724”,因为 724 是下一个 DELIMITER $$ CREATE TRIGGER `add_item_code` BEFORE INSERT ON `item` FOR EACH ROW BEGIN IF (NEW.item_code IS NULL OR NEW.item_code = '' ) THEN SET NEW.item_code = ( SELECT CONCAT("MM-",cat_code,"-",prod_code,id.item_id) FROM products,category,(SELECT AUTO_INCREMENT AS item_id FROM informatION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'comdb' AND TABLE_NAME = 'item') AS id WHERE products.prod_grp = NEW.prod_grp AND category.cat_type = NEW.cat_type ); END IF; END; $$ DELIMITER ; 值。>

但是,当我使用多个值进行插入时,INSERT INTO `item` (`prod_grp`,`name`,`stock`,`price`,`cat_type`) VALUES ('h & k','Crooks mirror','10','333.5','home') 值变为最新的值,从而导致错误item_id

item_code

比如说,如果最后一个 AUTO_INCREMENT 是 723,那么 AUTO_INCREMENT 会为这三个项目更新如下

item_id item_code
724 MM-hm-hk-724
725 MM-tl-dy-727
726 MM-el-hk-727

如您所见,最后两个 item_code 更新为错误的 item_id。 我根本不明白发生了什么。有人可以帮忙解决这个问题吗?

解决方法

一个技巧 - 您可以尝试使用用户定义的变量。

CREATE TRIGGER `add_item_code` 
BEFORE INSERT ON `item`
FOR EACH ROW 
BEGIN
    IF (NEW.item_code IS NULL OR NEW.item_code = '' ) THEN
        IF @add_item_code_autoincrement IS NULL THEN
            SELECT AUTO_INCREMENT 
            INTO @add_item_code_autoincrement
            FROM  INFORMATION_SCHEMA.TABLES
            WHERE TABLE_SCHEMA = DATABASE()
            AND TABLE_NAME = 'item';
        END IF;
        SET NEW.item_code = CONCAT("MM-",@add_item_code_autoincrement);
        SET @add_item_code_autoincrement = @add_item_code_autoincrement + 1;
    END IF;
END;

https://dbfiddle.uk/?rdbms=mysql_5.6&fiddle=97a725cd6a3850d52e6548ac1f09778c

这只是一个示例,因此删除了从其他表中检索值。变量名必须长而复杂,以避免任何干扰。

注意!此代码在并发插入中绝对不安全。如果执行并发插入,则此代码很可能会产生错误的值。如果您使用 INSERT .. ON DUPLICATE KEY UPDATE,它也会给出错误的结果。

此外,即使在最有利的条件下,此代码也可能给出错误的结果。因此,如果您仍然决定使用此技巧,请创建服务事件过程,该过程将检查生成值的正确性并在生成错误时更正它们。例如,它可以每分钟执行一次,并检查不超过 2 分钟的行。


额外的表格将是一种矫枉过正。但我很想知道解决方案。 – 死神

示意图:

CREATE additional_table (id INT AUTO_INCREMENT PRIMARY KEY) 
    AUTO_INCREMENT = {current AUTO_INCREMENT value for `item` table} ;

CREATE TRIGGER `add_item_code` 
BEFORE INSERT ON `item`
FOR EACH ROW 
BEGIN
    INSERT INTO additional_table VALUES (DEFAULT);
    SET @add_item_code_autoincrement := LAST_INSERT_ID();
--  DELETE FROM additional_table WHERE id < @add_item_code_autoincrement;
    IF (NEW.item_code IS NULL OR NEW.item_code = '' ) THEN
        SET NEW.item_code = CONCAT("MM-",@add_item_code_autoincrement);
    END IF;
END;