这个MySQL触发器是否是线程安全的?

时间:2015-01-27 10:40:23

标签: mysql triggers

我遇到与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没有按预期工作或者我错了!!!

1 个答案:

答案 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?。请仔细阅读答案中给出的例子。

请参阅文档