乐途乐途
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
  • 学习路径
  • 第1章 数据库基础与安装

    • MySQL 简介
    • MySQL 5.6 到 5.7 到 8.0 关键差异速查
    • 安装 MySQL 5.7
    • 连接与断开服务器
    • 创建数据库
    • 创建数据表
    • 数据库与数据表
    • 加载数据
    • 获取数据库信息
    • 批处理模式
    • SHOW 语句汇总
    • FLUSH 与 RESET 语句
    • my.cnf 核心参数
    • 字符集与排序规则
  • 第2章 SQL基础查询

    • SELECT
    • WHERE
    • ORDER BY
    • LIMIT
    • COUNT
    • 聚合函数
    • 比较运算符
    • 逻辑运算符
    • 算术运算符
    • 模式匹配
    • NULL 值处理
    • UPDATE
    • DELETE
    • REPLACE
    • SELECT INTO
  • 第3章 数据类型与运算符

    • 数值类型
    • 字符串类型
    • 日期时间类型
    • BIT 类型
    • ENUM 类型
    • SET 类型
    • JSON 类型
    • 类型转换
  • 第4章 函数与表达式

    • 字符串函数
    • 数值函数
    • 日期函数
    • 全文检索函数
  • 第5章 高级查询与子查询

    • JOIN
    • 子查询
    • UNION
    • GROUP BY
    • HAVING
    • DISTINCT
  • 第6章 表与索引

    • 数据定义语言
    • 修改表结构
    • 视图
    • 修改视图与检查选项
    • 外键
    • 索引
    • 唯一索引
    • 复合索引
    • 存储引擎对比
    • 分区表
    • 第一范式与第二范式
    • 第三范式与 BC 范式
    • 反范式设计
  • 第7章 存储过程与函数

    • 存储过程
    • 存储函数
    • 变量
    • 流程控制
    • 游标
    • 预处理语句
  • 第8章 事务与锁

    • 事务
    • 事务隔离级别
    • 锁机制
    • MVCC
    • 死锁专题分析
    • LOCK TABLES
    • XA 事务
  • 第9章 用户管理与安全

    • 用户管理
    • 权限管理
    • 角色
    • SQL 注入防范
  • 第10章 性能优化入门

    • 执行计划
    • 索引优化
    • 查询优化
    • 查询优化器提示
    • 慢查询日志
    • InnoDB 深入机制
    • InnoDB 专项优化
    • Performance Schema
    • sys Schema
  • 第11章 复制与高可用

    • 主从复制原理
    • 半同步复制配置
    • binlog 开启与 point-in-time 恢复
    • mysqldump 全库备份
    • mysqldump 单表与条件备份
    • mysqldump 恢复与导入
    • xtrabackup 全量热备
    • xtrabackup 准备与恢复
    • xtrabackup 增量与流式备份
  • 第12章 触发器与事件

    • 触发器
    • 事件调度器
  • 参考

    • MySQL 5.7 专业术语大全
    • MySQL 5.7 关键字与保留字大全

REPLACE

导学

当你需要"存在则更新,不存在则插入"时,通常要写 SELECT 判断 + UPDATE 或 INSERT 两条语句。REPLACE 提供了一种更简洁的替代方案——它先尝试删除旧记录,再插入新记录,从而实现"覆盖式"写入。

定义

REPLACE:DML 语句,用于插入数据,如果表中已存在相同主键或唯一键的记录,则先删除旧记录,再插入新记录。如果记录不存在,则直接插入。

核心语法

-- 与 INSERT 语法完全一致
REPLACE INTO 表名 (列1, 列2, ...) VALUES (值1, 值2, ...);

-- 支持 INSERT 的所有变体
REPLACE INTO 表名 SET 列1 = 值1, 列2 = 值2;
REPLACE INTO 表名 SELECT ... FROM 其他表;

演示数据准备

DROP TABLE IF EXISTS employees;

CREATE TABLE employees (
    emp_id INT PRIMARY KEY AUTO_INCREMENT,
    emp_name VARCHAR(20),
    dept VARCHAR(20),
    score DECIMAL(5,2)
);

INSERT INTO employees (emp_name, dept, score) VALUES
('大翔', '技术部', 100),
('白歌', '技术部', NULL);

当前 employees 表中的完整数据如下:

emp_idemp_namedeptscore
1大翔技术部100
2白歌技术部NULL

SQL 示例

场景一:主键冲突时覆盖更新

当前数据状态:见上文 employees 表完整数据。

执行语句:

REPLACE INTO employees (emp_id, emp_name, dept, score)
VALUES (2, '白歌', '产品部', 88);

操作后结果:

SELECT * FROM employees;
emp_idemp_namedeptscore
1大翔技术部100
2白歌产品部88

结果解读:emp_id = 2 已存在(白歌),REPLACE 的执行过程是:

  1. 先删除 emp_id = 2 的旧记录(技术部, NULL)
  2. 再插入新记录(产品部, 88)

最终效果看起来像是"更新"了白歌的部门和分数,但实际上是先删后插。

注意:AUTO_INCREMENT 主键如果显式指定了值(如本例的 emp_id = 2),则保持该值;如果省略主键让数据库自动生成,冲突删除后新插入的记录会获得新的自增值。

场景二:无冲突时直接插入

当前数据状态:见上文更新后的 employees 表。

执行语句:

REPLACE INTO employees (emp_id, emp_name, dept, score)
VALUES (3, '孔蓝', '运营部', 92);

操作后结果:

SELECT * FROM employees;
emp_idemp_namedeptscore
1大翔技术部100
2白歌产品部88
3孔蓝运营部92

结果解读:emp_id = 3 不存在,因此 REPLACE 直接插入新记录,行为与 INSERT 完全一致。返回受影响行数为 1。

场景三:REPLACE 与 INSERT ... ON DUPLICATE KEY UPDATE 的对比

当前数据状态:重新初始化:

DELETE FROM employees WHERE emp_id = 3;
UPDATE employees SET dept = '技术部', score = NULL WHERE emp_id = 2;
emp_idemp_namedeptscore
1大翔技术部100
2白歌技术部NULL

执行语句(REPLACE):

REPLACE INTO employees (emp_id, emp_name, dept, score)
VALUES (2, '白歌', '产品部', 88);

执行语句(INSERT ... ON DUPLICATE KEY UPDATE):

INSERT INTO employees (emp_id, emp_name, dept, score)
VALUES (2, '白歌', '产品部', 88)
ON DUPLICATE KEY UPDATE dept = VALUES(dept), score = VALUES(score);

两种方式的最终表状态相同:

emp_idemp_namedeptscore
1大翔技术部100
2白歌产品部88

但内部机制差异很大:

特性REPLACEINSERT ... ON DUPLICATE KEY UPDATE
实现方式先删除旧行,再插入新行直接更新旧行的指定字段
触发器行为触发 DELETE + INSERT 触发器只触发 UPDATE 触发器
自增值变化删除后重新插入,自增值可能变化不删除,自增值不变
未指定字段新记录中未指定的字段变为默认值未指定的字段保持原值
性能较差(两次操作)较好(单次更新)
外键约束删除可能触发级联删除不触发级联删除

结果解读:

  • REPLACE 是"暴力覆盖":旧记录完全消失,新记录重新生成
  • INSERT ... ON DUPLICATE KEY UPDATE 是"精准更新":只修改指定字段,保留其他字段原值
  • 生产环境优先使用 INSERT ... ON DUPLICATE KEY UPDATE,更安全、性能更好

场景四:REPLACE 的陷阱——未指定字段变默认值

当前数据状态:重新初始化:

UPDATE employees SET dept = '技术部', score = NULL WHERE emp_id = 2;
emp_idemp_namedeptscore
1大翔技术部100
2白歌技术部NULL

执行语句:

REPLACE INTO employees (emp_id, emp_name, dept)
VALUES (1, '大翔', '产品部');

操作后结果:

SELECT * FROM employees;
emp_idemp_namedeptscore
1大翔产品部NULL
2白歌技术部NULL

结果解读:REPLACE 只指定了 emp_id、emp_name、dept,没有指定 score。由于 REPLACE 是先删除再插入,新插入的记录中未指定的 score 会变为默认值(本例中 score 没有 DEFAULT,因此为 NULL)。大翔原来的 score = 100 被"意外"丢失了!

这是 REPLACE 最常见的陷阱。相比之下,INSERT ... ON DUPLICATE KEY UPDATE 只更新指定字段,不会丢失未提及的字段值。

常见误区

误区正解
"REPLACE 和 UPDATE 一样只修改指定字段"不是。REPLACE 是先删除旧记录再插入新记录,未指定的字段会丢失或变默认值。
"REPLACE 比 INSERT ... ON DUPLICATE KEY UPDATE 更好"恰恰相反。生产环境优先用 INSERT ... ON DUPLICATE KEY UPDATE,性能更好且不会丢失字段。
"REPLACE 不会触发触发器"会触发。REPLACE 触发 DELETE 触发器(旧记录)+ INSERT 触发器(新记录)。
"REPLACE 的自增值不变"会变。旧记录删除后,新插入的记录如果由数据库生成自增值,会得到新值。
"REPLACE 可以用于没有主键/唯一键的表"不能。没有冲突检测依据时,REPLACE 行为等同于 INSERT。

面试考点

Q:REPLACE 和 INSERT ... ON DUPLICATE KEY UPDATE 的区别?

  1. REPLACE 是先删除旧记录再插入新记录,会丢失未指定字段的值,触发 DELETE + INSERT 触发器,自增值可能变化;2. INSERT ... ON DUPLICATE KEY UPDATE 是直接更新旧记录的指定字段,保留其他字段原值,只触发 UPDATE 触发器,自增值不变。生产环境优先用后者。

Q:REPLACE 的适用场景是什么?

适合简单场景:全量覆盖写入,不关心旧记录的其他字段值。例如:定时全量同步外部数据源,每次同步直接用 REPLACE 覆盖。但大多数业务场景更适合 INSERT ... ON DUPLICATE KEY UPDATE。

Q:REPLACE 对自增主键的影响?

如果显式指定主键值(如 REPLACE INTO t (id, ...) VALUES (5, ...)),则保持该值;如果省略主键让数据库自动生成,删除旧记录后新插入的记录会获得新的自增值(旧值不会复用)。这可能导致自增值跳跃增长。

Q:为什么生产环境不推荐 REPLACE?

  1. 先删后插的性能开销大于直接更新;2. 未指定字段会丢失或变默认值,容易误删数据;3. 触发器行为复杂(DELETE + INSERT 两次触发);4. 有外键时,删除可能触发级联删除,导致关联数据意外丢失。

小结

  • REPLACE 实现"存在则覆盖,不存在则插入",但内部是先删除再插入
  • 未指定的字段会丢失或变为默认值,这是最常见的陷阱
  • 生产环境优先使用 INSERT ... ON DUPLICATE KEY UPDATE,更安全高效
  • REPLACE 会触发 DELETE + INSERT 两次触发器,自增值可能变化
  • 有外键约束的表慎用 REPLACE,避免级联删除风险

下一章引子:学会了增删改查四大操作,接下来深入了解 MySQL 中各种数据类型的特性和选型原则。

上一页
DELETE
下一页
SELECT INTO