我正在尝试创建一个生成并存储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
,而INSERT
之前我没有修改auto_increment
值:
错误1442(HY000):无法更新存储的函数/触发器中的表'Table1',因为它已被调用此存储函数/触发器的语句使用。
答案 0 :(得分:5)
在插入行之后,您无法再修改的值。因此,SET NEW.column
仅适用于BEFORE
触发器。
此外,您无法使用常规UPDATE
because:
存储的函数或触发器无法修改已经存在的表 被调用的语句用于(读或写) 功能或触发器。
最后,在BEFORE INSERT
触发器中,尚未生成AUTO_INCREMENT
值,NEW.id
为0
。
技巧:在BEFORE
触发器中,手动检查表定义中的下一个AUTO_INCREMENT
值:
我假设如果innodb_autoinc_lock_mode = 0
它可以与InnoDB一起使用,但我无法确定。
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
/ {{1获取对表的独占锁定并且不会发生并发访问。
使用InnoDB,这不太明显。对于“traditional lock mode”,手册说:
InnoDB使用一种称为表级AUTO-INC锁的特殊锁 插入带有AUTO_INCREMENT列的表。这种锁通常是 持有到声明的末尾
我认为在这种情况下这是安全的。
我不熟悉这些概念,所以我无法确定。这看起来确实很可疑。
[编辑2]
我使用innodb_autoinc_lock_mode
的不同设置运行以下测试:
创建表t( ai INT AUTO_INCREMENT PRIMARY KEY, trigval INT, 旗帜BOOL );
表格上的触发器使用上述方法DELETE
。
在一个事务中,长INSERT由:
生成SET NEW.trigval = next_ai
在第二次交易中,我不断发表以下声明:
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
。
但是,我没想到,使用模式INSERT
(默认值)和1
,这种方法明显错误。 2
按步骤更新。这是我得到的结果:
+-------+---------+------+ | ai | trigval | flag | +-------+---------+------+ | 3 | 4 | 0 | | 5 | 8 | 0 | | 9 | 16 | 0 | | 17 | 32 | 0 | | 33 | 64 | 0 | | 65 | 128 | 0 | ...