问大家一个问题,在MySql批量插入的时候,你们如何避免插入重复的数据,下面给出几个方案:
🛠 一、最佳方案:ON DUPLICATE KEY UPDATE
适用场景:存在唯一索引/主键冲突时需更新其他字段(如时间戳、计数器)。
原理:冲突时执行更新操作,不冲突则正常插入。
示例:
INSERT INTO user (id, name, age)
VALUES (1, '张三', 25), (2, '李四', 30)
ON DUPLICATE KEY UPDATE age = VALUES(age);
优势:
✅ 精确处理唯一键冲突,其他错误仍会抛出(安全)。
✅ 支持批量操作,高效更新重复数据。
⚡ 二、忽略重复:INSERT IGNORE
适用场景:仅需跳过重复记录,不更新其他字段。
示例:
INSERT IGNORE INTO user (id, name)
VALUES (1, '张三'), (2, '李四');
注意:
⚠️ 会忽略所有错误(如数据类型错误),仅适合数据质量高的场景。
🔄 三、替换重复:REPLACE INTO
适用场景:需彻底覆盖重复记录(先删除再插入)。
示例:
REPLACE INTO user (id, name)
VALUES (1, '张三'), (2, '李四');
缺点:
❌ 自增 ID 可能变化(因先删后插)。
❌ 触发 DELETE + INSERT 事件(可能影响触发器)。
🔍 四、条件插入:INSERT ... WHERE NOT EXISTS
适用场景:依赖非唯一键条件去重(如业务逻辑)。
示例:
INSERT INTO user (name, role)
SELECT '张三', 'admin' FROM DUAL
WHERE NOT EXISTS (SELECT 1 FROM user WHERE name='张三' AND role='admin');
注意:
⚠️ 性能较低(需子查询),大数据量避免使用。
📌 关键前提:创建唯一索引!
ALTER TABLE user ADD UNIQUE INDEX idx_unique_name (name); -- 单字段唯一索引
ALTER TABLE user ADD UNIQUE INDEX idx_name_role (name, role); -- 联合唯一索引
⛔ 无唯一索引则所有方案失效!
💎 总结:如何选择?
方案 | 适用场景 | 是否推荐 |
---|---|---|
ON DUPLICATE KEY UPDATE | 冲突时需更新字段 | ⭐⭐⭐⭐⭐ |
INSERT IGNORE | 简单跳过重复(数据质量高) | ⭐⭐ |
REPLACE INTO | 需完全覆盖旧数据 | ⭐ |
WHERE NOT EXISTS | 非索引条件去重 | ⭐ |
💡 实际建议:
- 首选
ON DUPLICATE KEY UPDATE
(安全+灵活),尤其 MyBatis 等框架可轻松集成批量操作。- 海量数据时,提前按唯一键分组,减少事务锁竞争。
- 禁止重复时,务必提前创建唯一索引!
所有方案源码示例,请详见官方文档👉 (https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html)