8

我正在尝试创建一个触发器,为 auto_increment 索引生成和存储哈希,但我尝试过的所有解决方案都不起作用:

DELIMITER //
CREATE TRIGGER insertTable1 AFTER INSERT ON Table1
FOR EACH ROW 
   BEGIN
     SET NEW.hash = calc_hash_udf(NEW.id);
   END //
DELIMITER ;;

它说我不能在NEW之后INSERT和之前修改 aINSERT我没有auto_increment值:

错误 1442 (HY000):无法更新存储函数/触发器中的表 'Table1',因为它已被调用此存储函数/触发器的语句使用。

4

1 回答 1

6

插入行,您无法再修改该值。因此SET NEW.column仅在BEFORE触发器中可用。

您也不能使用常规UPDATE因为

存储的函数或触发器不能修改已被调用函数或触发器的语句使用(用于读取或写入)的表。

最后,在BEFORE INSERT触发器中,该AUTO_INCREMENT值尚未生成,并且NEW.id0

诀窍:在BEFORE触发器中,手动检查表定义中的下一个AUTO_INCREMENT值:

警告:这只适用于 MyISAM,不适用于 InnoDB

它可以与 InnoDB 一起使用,innodb_autoinc_lock_mode = 0但我无法确定。

DELIMITER //    

    CREATE TRIGGER insertTable1 BEFORE INSERT ON Table1 FOR EACH ROW
    BEGIN
        DECLARE next_ai INT;
        SELECT auto_increment INTO next_ai
          FROM information_schema.tables
          WHERE table_schema=DATABASE() AND table_name = 'Table1';
        SET NEW.hash = calc_hash_udf(next_ai);
    END //

DELIMITER ;

[编辑 1]

至于这种方法的并发证明属性,我可以说:

  • 使用 MyISAM,只有表锁可用,安全性是显而易见的:任何INSERT/ UPDATE/都可以获得表上的排他锁DELETE,并且不会发生并发访问。

  • 对于 InnoDB,这不太明显。对于“传统锁定模式”,手册说:

InnoDB 使用称为表级 AUTO-INC 锁的特殊锁来插入具有 AUTO_INCREMENT 列的表。这个锁通常被持有到语句的结尾

我想在这种情况下这是安全的。

我不熟悉这些概念,所以我无法确定。看起来确实很可疑。

[编辑 2]

我已经使用不同的设置运行了以下测试innodb_autoinc_lock_mode

CREATE TABLE t (ai INT AUTO_INCREMENT PRIMARY KEY, trigval INT, flag BOOL);

表上的触发器SET NEW.trigval = next_ai使用上述方法。

在一个事务中,一个长 INSERT 是由:

INSERT INTO t SELECT null, null, 0 FROM (SELECT * FROM a_very_big_table) AS tmp;

在第二次交易中,我不断发出以下声明:

INSERT INTO t VALUES (null, null, 1);

最后,我搜索差异:

SELECT * FROM t WHERE ai <> trigval;

使用innodb_autoinc_lock_mode = 0("traditional") 似乎是安全的。任何并发插入表的尝试都被锁定,直到 long 完成INSERT

但是,我没想到,使用模式1(默认)和2,这种方法显然是错误的。information_schema.tables.auto_increment是按步骤更新的。这是我得到的结果:

+--------+---------+------+
| 艾| 三角 | 标志 |
+--------+---------+------+
| 3 | 4 | 0 |
| 5 | 8 | 0 |
| 9 | 16 | 0 |
| 17 | 32 | 0 |
| 33 | 64 | 0 |
| 65 | 128 | 0 |
...

于 2013-06-07T13:53:58.293 回答