我遇到与here所述相同的问题,我认为答案https://stackoverflow.com/a/22343265/297487是一个很好的解决方案,但我对此答案还有另外一个问题。
以下触发器(从答案中复制)是否是线程安全的?我的意思是如果将两个并发记录插入到表中,那么" priority" column(如有问题所述)具有一致的值(与id相同的值)?
delimiter //
drop trigger if exists bi_table_name //
create trigger bi_table_name before insert on table_name
for each row begin
set @auto_id := ( SELECT AUTO_INCREMENT
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME='table_name'
AND TABLE_SCHEMA=DATABASE() );
set new.priority= @auto_id;
end;
//
delimiter ;
我们如何解释每一行""条款? 假设MySQL想要插入两个并发行。这个触发器是如何工作的?
一种解释如下:
MySQL锁定表,在插入其中一行(并发记录之一)之前,MySQL触发器启动并获取当前的AUTO_INCREMENT值并将其设置为" priority"列然后插入记录。之后,MySQL开始插入另一条记录,然后同样的情况适用于新记录。
另一种解释可能如下:
当两个并发记录被插入MySQL时,MySQL会锁定表,然后在插入两个并发记录之前,触发器开始,并且#34;对于每一行"子句在两个记录之间迭代并设置" priority"列值为相同的值,然后在数据库中插入两个并发记录。在这种情况下,触发器无法按预期工作。
上述哪一种解释是正确的?
我有下表:
CREATE TABLE `t_file` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8_persian_ci NOT NULL,
`p_name` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `p_name_2` (`p_name`)
) ENGINE=InnoDB AUTO_INCREMENT=206284 DEFAULT CHARSET=utf8 COLLATE=utf8_persian_ci;
插入行时,我想插入p_name
的值与id
相同。
设置trigger
值的p_name
如下(从您的代码中复制)
delimiter $$
drop trigger if exists file_p_name $$
create trigger file_p_name before insert on t_file
for each row begin
set @id := ( SELECT AUTO_INCREMENT
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME='t_file'
AND TABLE_SCHEMA=DATABASE() );
set new.p_name= @id;
end;
$$
delimiter ;
在我们的应用程序中,我围绕在t_file
表中插入try catch
的代码,几乎总是一切正常,但有时(并发插入t_file
表),i请参阅我们的应用程序日志中的以下异常:
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry \'387456\' for key \'p_name_2\''
似乎trigger
没有按预期工作或者我错了!!!
答案 0 :(得分:0)
answer referred in your question已经被我发布了一段时间。
在"For Each Row"
中,NEW
是在上下文中插入的对应的新行。 set new.xxx
仅适用于该行,但不适用于批次中的'for all rows'
。所以不会发生碰撞,不应该出现失败的问题。
我也回答了类似的问题 How does “for each row” work in triggers in mysql?。请仔细阅读答案中给出的例子。
请参阅文档: