您好,我有一个仅两个字段的简单MySQL InnoDB表:
我要从各种来源并行导入一些数据,并且需要确保在插入时不重复这些数据,因此我需要执行以下操作:
SELECT `id` FROM `table` WHERE `name` = <name>;
if `id` <= 0
INSERT INTO `table` SET `name` = "<name>";
return AUTO_INCREMENT
else return `id`
这可以工作99.9999%的时间,但是由于两个SELECT都返回id
<= 0,所以两个或多个不同的脚本正在插入相同的数据,这可能会发生(并且发生在我身上),因此INSERT都会发生,并且其中一个会引发错误。
我有两个可能的解决方案,但我不确定哪种方法最有效。
另外一条信息:最初导入不会在表中找到元素,但是随着插入更多元素,被发现的可能性会增加。经过一番粗略的计算,决赛桌将有大约7到1千万条记录:
SELECT `id` FROM `table` WHERE `name` = <name>;
if `id` <= 0
INSERT IGNORE INTO `table` SET `name` = "<name>";
get AUTO_INCREMENT
if AUTO_INCREMENT <=0
SELECT `id` FROM `table` WHERE `name` = <name>;
return `id`
else return AUTO_INCREMENT
else return `id`
或者
INSERT IGNORE INTO `table` SET `name` = "<name>";
get AUTO_INCREMENT
if AUTO_INCREMENT <=0
SELECT `id` FROM `table` WHERE `name` = <name>;
return `id`
else return AUTO_INCREMENT
您遇到了比赛情况。当您的代码检测到有必要进行新的插入时,那么您的两个客户就争先成为第一个插入该值的客户。这是赢家通吃的。您需要编写代码来避免这种竞争情况。幸运的是,SQL是专门设计的,因此可以做到这一点。
在这里,您有两种选择,这两种选择都特定于MySQL的SQL方言。
一种是使用内置功能LAST_INSERT_ID()
。它达到了我相信您的意思get AUTO_INCREMENT
。
另一种是使用INSERT ... ON DUPLICATE KEY UPDATE
。
您的逻辑似乎打算做两件事:
name
值在表中,如果尚未在表中,则将其放置在表中。id
与名称值关联的值。您可以这样做。
INSERT IGNORE INTO `table` (name) VALUES (<name>);
SELECT id FROM `table` WHERE name = <name>;
注意,该INSERT IGNORE
操作不会被命中数据库的不同程序之间的竞争条件所捕获,因为它是一条SQL语句。
您可以使用进行优化LAST_INSERT_ID()
。
INSERT IGNORE INTO `table` (name) VALUES (<name>);
if (LAST_INSERT_ID()=0) then do the select.
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句