我正在尝试创建一个生成并存储auto_increment索引的哈希的触发器,但我尝试过的所有解决方案都不起作用:
DELIMITER //
CREATE TRIGGER insertTable1 AFTER INSERT ON Table1
FOR EACH ROW
BEGIN
SET NEW.hash = calc_hash_udf(NEW.id);
END //
DELIMITER ;;
Run Code Online (Sandbox Code Playgroud)
它说我不能修改一个NEW之后INSERT,之前INSERT我没有这个auto_increment值:
错误1442(HY000):无法更新存储函数/触发器中的表'Table1',因为它已被调用此存储函数/触发器的语句使用.
插入行后,您无法再修改该值.因此SET NEW.column仅在BEFORE触发器中可用.
您也可以不使用常规的UPDATE要么是因为:
存储的函数或触发器不能通过调用函数或触发器的语句修改已经使用(用于读取或写入)的表.
最后,在BEFORE INSERT触发器中,AUTO_INCREMENT尚未生成该值,并且NEW.id是0.
技巧:在BEFORE触发器中,手动检查表定义以获取下一个AUTO_INCREMENT值:
我想它可以与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 ;
Run Code Online (Sandbox Code Playgroud)
[编辑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;
Run Code Online (Sandbox Code Playgroud)
在第二次交易中,我不断发表以下声明:
INSERT INTO t VALUES (null, null, 1);
Run Code Online (Sandbox Code Playgroud)
最后,我搜索了差异:
SELECT * FROM t WHERE ai <> trigval;
Run Code Online (Sandbox Code Playgroud)
随着innodb_autoinc_lock_mode = 0("传统"),这似乎是安全的.插入表中的任何并发尝试都将被锁定,直到完成long INSERT.
但是,我没想到,使用模式1(默认)2,这种方法显然是错误的.information_schema.tables.auto_increment按步骤更新.这是我得到的结果:
+-------+---------+------+ | ai | trigval | flag | +-------+---------+------+ | 3 | 4 | 0 | | 5 | 8 | 0 | | 9 | 16 | 0 | | 17 | 32 | 0 | | 33 | 64 | 0 | | 65 | 128 | 0 | ...