好吧,查询好吗?我试图遵循替换条款的行为,如果您不知道,这是损失。

大家好,我是开发团队的狂野团队成员 Mandai。
这次,我想更深入地了解一下 REPLACE 子句的行为,您可能每天都在使用它,却从未仔细思考过。
如何更新数据?
我们公司使用 MySQL 作为系统开发的主要关系数据库管理系统 (RDBMS)。
通常情况下,当更新带有唯一约束的表时,
- SELECT 并检查重复项,然后分支执行 INSERT 或 UPDATE 操作。
- 如果尝试插入数据时发现重复项,则捕获异常并继续进行更新处理。
你可能被迫在上述两个选项中做出选择,但实际上(也不完全是),还可以使用 REPLACE 子句进行更新。
如果您认为 REPLACE 子句只是像字面意思那样替换数据,那么执行此子句可能会导致数据不一致,并导致意想不到的情况。
我们来看一个简单的例子,看看它是如何运作的。
让我们看看它的实际表现。
首先,创建一个如下所示的表格:
mysql> CREATE TABLE `users` (`id` INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, `name` VARCHAR(16) NOT NULL UNIQUE, `level` INT UNSIGNED NOT NULL DEFAULT 1); Query OK, 0 rows affected (0.02 sec) mysql> DESC `users`; +-------+-----+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+------+------+-----+---------+----------------+ | id | int(10) unsigned | NO | PRI | NULL | auto_increment | | name | varchar(16) | NO | UNI | NULL | | | level | int(10) unsigned | NO | | 1 | | +-------+------------------+------+-----+---------+----------------+ 3 行数据 (0.00 秒)
名称字段被设置为唯一键。
接下来,我们将输入一些简单的示例数据。
这次,我尝试使用generatedata.com
我认为现场气氛大概会是这样的:
mysql> INSERT INTO `users` (`name`,`level`) VALUES ("Pamela",8),("Dexter",4),("Ava",1),("Kelly",8),("Leila",2),("Quin",8),("Salvador",8),("Orli",2),("Ignacia",9),("Brennan",8); 查询成功,影响 10 行 (0.00 秒) 记录数:10 重复数:0 警告数:0 mysql> SELECT * FROM `users`; | Quin | 8 | | 7 | Salvador | 8 | | 8 | Orli | 2 | | 9 | Ignacia | 9 | | 10 | Brennan | 8 | +----+----------+-------+ 10 行结果 (0.00 秒)
现在,我们来尝试插入一条名称重复的记录。
mysql> INSERT INTO `users` (`name`,`level`) VALUES ("Pamela",1); ERROR 1062 (23000): Duplicate entry 'Pamela' for key 'name' mysql> SELECT * FROM `users`; +----+----------+-------+ | id | name | level | +----+----------+-------+ | 1 | Pamela | 8 | | 2 | Dexter | 4 | | | 3 | Ava | 1 | | 4 | Kelly | 8 | | 5 | Leila | 2 | | 6 | Quin | 8 | | 7 | Salvador | 8 | | 8 | Orli | 10 rows in set (0.00 sec)
由于重复项,发生错误。
这是预期行为。
通常情况下,你会在这里使用 UPDATE 子句来更新记录。
mysql> UPDATE `users` SET `level`=10 WHERE `name` = "Pamela"; 查询成功,影响 1 行 (0.00 秒) 匹配行数:1 更改行数:1 警告数:0 mysql> select * from users; +----+----------+-------+ | id | name | level | +----+----------+-------+ | 1 | Pamela | 10 | | 2 | Dexter | 4 | | 3 | Ava | 1 | | 4 | Kelly | 8 | | 5 | Leila | 2 | | 6 | Quin | in set (0.00 秒)
现在让我们尝试使用 REPLACE 子句更新记录。
mysql> REPLACE INTO `users` (`name`,`level`) VALUES ("Pamela",1); Query OK, 2 rows affected (0.00 sec) mysql> SELECT * FROM `users`; 3 | Ava | 1 | | 4 | Kelly | 8 | | 5 | Leila | 2 | | 6 | Quin | 8 | | 7 | Salvador | 8 | | 8 | Orli | 2 | | 9 | Ignacia | 9 | sec)
这时,你有没有注意到发生了可怕的事情?
没错,名称为“Pamela”的记录的主键不知何故被更改了!
让我们仔细看看这个事实,它就像稻川纯二的鬼故事一样恐怖。
REPLACE 条款不仅仅是替换。
这一点从之前的实验中已经很明显了,但为什么会发生这种情况呢?
顺便一提,id 中缺少 11 的原因是执行了 INSERT 语句,但这并非本文要讨论的重点。
简而言之,原因在于:
REPLACE 子句“在 DELETE 操作后插入一条具有相同数据的记录”。
这很可怕。
主键自动更改
的想法如果你经常使用它,认为它是一个方便的查询,可以自动判断是插入还是更新,你
可能还没踩到任何地雷,但不知不觉中,你可能会发现自己身处雷区。
然而,这种现象发生在
- 具有自动递增的主键
- 同时,还有一个字段是唯一键。
- 当唯一键重复时
我
认为正确的答案是,他们在了解 REPLACE 子句的行为后并没有实现它。
还有一种类似的语法叫做“INSERT ... ON DUPLICATE KEY UPDATE”,但
它不适用于基于语句的复制或具有复合主键(唯一键)的表
,因此我认为它的用途有限。
此外,许多框架的 O/R 映射器也不支持它(因为它是一种 MySQL 方言,而不是标准 SQL),所以如果使用它,您将无法获得 O/R 映射器的优势。
尽管如此,有报告称 ON DUPLICATE KEY UPDATE 语法的处理速度比 SELECT → INSERT (UPDATE) 快得多,因此
如果您的 MySQL 系统处理数据更新的时间过长,则值得一试。
MySQL 5.6 系列日文文档
MySQL 5.7 系列文档(英文)
(内容与 5.7 系列文档的英文版大致相同)
此外,INSERT 操作会不必要地累加自增值,这可能会
导致主键耗尽的悲剧。
为了安全起见,我认为 SELECT → INSERT(或 UPDATE)是最安全的选择。
哇, generatedata.com真好用。
如果您想咨询开发专业人员
在《超越》中,我们将富裕的往绩,技术和专有技术结合在系统开发中,迄今为止,我们已经使用OSS技术和云技术(例如AWS)来创建具有可靠质量和出色成本性能的Web系统的合同开发。
我们还使用Web系统/应用基础架构的构建和操作的技术和专业知识来研究自己API的服务器端/后端开发和链接开发,用于大规模,高度加载的游戏,应用程序和数字内容。
如果您在开发项目方面遇到麻烦,请访问下面的网站。
5