更新时间:2023-01-22 16:49:07
我建议使用 INSERT...ON DUPLICATE KEY UPDATE
.
如果您使用INSERT IGNORE
,那么如果导致重复键,该行实际上不会被插入.但该语句不会产生错误.相反,它会生成警告.这些情况包括:
If you use INSERT IGNORE
, then the row won't actually be inserted if it results in a duplicate key. But the statement won't generate an error. It generates a warning instead. These cases include:
PRIMARY KEY
或 UNIQUE
约束的列中插入重复键.NOT NULL
约束的列中.PRIMARY KEY
or UNIQUE
constraints. NOT NULL
constraint.如果你使用REPLACE
,MySQL实际上在内部做了一个DELETE
后跟一个INSERT
,这有一些意想不到的副作用:
If you use REPLACE
, MySQL actually does a DELETE
followed by an INSERT
internally, which has some unexpected side effects:
REPLACE
.DELETE
上触发的触发器.更正:REPLACE
和 INSERT...ON DUPLICATE KEY UPDATE
都是 MySQL 特有的非标准专有发明.ANSI SQL 2003 定义了一个 MERGE
语句,可以解决同样的(甚至更多)需求,但是 MySQL 不支持 MERGE
语句.
correction: both REPLACE
and INSERT...ON DUPLICATE KEY UPDATE
are non-standard, proprietary inventions specific to MySQL. ANSI SQL 2003 defines a MERGE
statement that can solve the same need (and more), but MySQL does not support the MERGE
statement.
有用户试图编辑此帖子(编辑被版主拒绝).该编辑试图添加一个声明,即 INSERT...ON DUPLICATE KEY UPDATE
会导致分配一个新的自动递增 ID.确实,新的id是生成的,但是在改变的行中并没有使用.
A user tried to edit this post (the edit was rejected by moderators). The edit tried to add a claim that INSERT...ON DUPLICATE KEY UPDATE
causes a new auto-increment id to be allocated. It's true that the new id is generated, but it is not used in the changed row.
请参阅下面的演示,使用 Percona Server 5.5.28 进行测试.配置变量innodb_autoinc_lock_mode=1
(默认):
See demonstration below, tested with Percona Server 5.5.28. The configuration variable innodb_autoinc_lock_mode=1
(the default):
mysql> create table foo (id serial primary key, u int, unique key (u));
mysql> insert into foo (u) values (10);
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 1 | 10 |
+----+------+
mysql> show create table foo\G
CREATE TABLE `foo` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`u` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `u` (`u`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1
mysql> insert into foo (u) values (10) on duplicate key update u = 20;
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 1 | 20 |
+----+------+
mysql> show create table foo\G
CREATE TABLE `foo` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`u` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `u` (`u`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
上面演示了IODKU语句检测到重复,并调用更新来改变u
的值.请注意,AUTO_INCREMENT=3
表示生成了 id,但未在行中使用.
The above demonstrates that the IODKU statement detects the duplicate, and invokes the update to change the value of u
. Note the AUTO_INCREMENT=3
indicates an id was generated, but not used in the row.
而 REPLACE
确实删除原始行并插入新行,生成并存储一个新的自增 ID:
Whereas REPLACE
does delete the original row and inserts a new row, generating and storing a new auto-increment id:
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 1 | 20 |
+----+------+
mysql> replace into foo (u) values (20);
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 3 | 20 |
+----+------+