在Hibernate里面有一个非常好用的方法,是由
org.hibernate.Session
提供的,这个方法的名称叫做saveOrUpdate
。一些小伙伴发现了MySQL里面有一种写法叫做
REPLACE INTO
。有一些人会以为
REPLACE INTO
和saveOrUpdate
一样,实际这是错误的,本文带你详细了解一下REPLACE INTO
语句。
一、认识REPLACE INTO
REPLACE INTO
是 SQL 中用于插入或更新数据的一种语句,它结合了 INSERT
和 UPDATE
的功能,主要用于处理重复数据的情况。但是这个UPDATE
有点不一样,我们仔细看看。
官方介绍点这里

1.1 基本语法
REPLACE INTO
的基本语法如下:
sql
REPLACE INTO table_name (column1, column2, ..., columnN)
VALUES (value1, value2, ..., valueN);
或者:
sql
REPLACE INTO table_name
SET column1 = value1, column2 = value2, ..., columnN = valueN;
1.2 简单使用
- 现在我们有这么一张用户表,建表语句如下:
sql
CREATE TABLE `user_info` (
`id` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户id',
`risk_score` int NOT NULL DEFAULT '0' COMMENT '风险评分 0-100 (不可超出该范围)',
`risk_level` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0-安全 1-低风险 2-中风险 3-高风险',
`register_time` datetime NOT NULL COMMENT '注册时间',
`created` datetime NOT NULL COMMENT '创建时间(北京时间)',
`updated` datetime DEFAULT NULL COMMENT '修改时间(北京时间)',
`creator` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '创建人',
`updater` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '更新人',
PRIMARY KEY (`id`),
KEY `idx_updated` (`updated`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户安全信息表';
- 我们先把表里面插入一行数据:
sql
INSERT INTO `user_info`(`id`, `risk_score`, `risk_level`, `register_time`, `created`, `updated`, `creator`, `updater`) VALUES ('11-00762ef32f454892ad2ed7b2fc49d409', 20, 1, '2024-02-29 14:23:25', '2025-04-29 14:13:58', '2025-04-29 14:13:58', 'admin', 'admin');
插入结果如下:

- 现在我们写一个
REPLACE INTO
语句,执行看看结果:
sql
REPLACE INTO `user_info`(`id`, `risk_score`, `risk_level`, `register_time`, `created`, `updated`, `creator`, `updater`) VALUES ('11-00762ef32f454892ad2ed7b2fc49d409', 40, 1, '2024-02-29 14:23:25', '2025-04-30 14:13:58', '2025-04-30 14:13:58', 'admin30', 'admin30');

注意:这里我们很明显的可以看出来,所影响的行数是2
- 查询原表记录如下:得到结果,表里面还是一条记录,为什么呢?

二、研究REPLACE INTO执行原理
上面1.2的简单使用,我们发现当执行1.2里面的语句的时候,所影响的行数是2,那么是不是所有的REPLACE INTO
语句,影响行数都是2呢?
2.1 来个案例
- 首先我们准备下面这么一条SQL:
sql
REPLACE INTO `user_info`(`id`, `risk_score`, `risk_level`, `register_time`, `created`, `updated`, `creator`, `updater`) VALUES ('22-00762ef32f454892ad2ed7b2fc49d222', 20, 1, '2024-02-29 14:23:25', '2025-04-30 14:13:58', '2025-04-30 14:13:58', 'test', 'test');
执行之后我们得到的结果如下:可以很明显的看到,这条sql执行所影响的行数是1。

2.2 找原因
通过上面1.2和2.1里面的案例,我们发现,REPLACE INTO
语句,有的时候影响行数是1,有的时候影响行数是2,那么为什么呢?
我们一起看看官方是怎么解释的:

官方文档有大量的详细的介绍(可以点击这里仔细看看);上面截图部分是我找的比较直白介绍的内容:
他说:当在MySQL使用REPLACE INTO
语句的时候,
-
1、首先尝试插入新行到表中;
-
2、当由于主键或唯一索引发生 duplicate-key 错误而导致插入失败时
-
先从表中删除具有 duplicate 键值的冲突行
-
再次尝试将新行插入表中
-
到这里相信大家就知道为什么有的影响行数是1.有的影响行数是2了。说白了,REPLACE INTO
的主要功能是插入数据,但如果表中已经存在与插入数据的主键或唯一键冲突的记录,它会先删除旧记录,再插入新记录。所以他不是插入或者更新这种操作,切记。
三、存在即合理(哪些场景适用)
实际这个不用多说,大家理解了原理相比也能知道哪里使用合适,这里我罗列一些,大家实际业务按需求分析。

四、注意事项
使用 REPLACE INTO
语句时,有一些特别棒需要注意的事项,这些事项涉及语法、性能、数据完整性、事务处理等方面。
-
依赖唯一性约束 :
REPLACE INTO
依赖于表中的主键或唯一键约束。如果表中没有定义主键或唯一键,REPLACE INTO
将无法正确判断哪些记录是重复的,从而无法执行替换操作。 -
删除和插入操作 :
REPLACE INTO
实际上是先删除重复的记录,再插入新的记录。这意味着它会执行两次操作(删除 + 插入),可能会比单纯的INSERT
或UPDATE
操作更耗时,尤其是在数据量较大的表中 -
索引影响:删除和插入操作都会影响索引。删除操作会更新索引,插入操作也会更新索引,这可能会导致索引的维护成本增加,进而影响性能。
-
外键约束:如果表中存在外键约束,删除操作可能会导致外键关联的完整性问题。例如,如果被删除的记录被其他表引用,可能会导致外键约束冲突。当然,谁家好人用外键啊,哈哈。
五、总结
REPLACE INTO
是一个强大的 SQL 语句,但在使用时需要注意其依赖的唯一性约束、性能影响、数据完整性问题以及事务处理等。在实际应用中,建议根据具体的业务需求和数据特点选择合适的操作方式,并在使用前进行充分的测试和验证。
另外:再次强调,他是插入或者删除插入,不是插入或者更新,别搞混了。
希望本文对您有所帮助。如果有任何错误或建议,请随时指正和提出。
同时,如果您觉得这篇文章有价值,请考虑点赞和收藏。这将激励我进一步改进和创作更多有用的内容。
感谢您的支持和理解!