MySQL 提供 INSERT、REPLACE、INSERT IGNORE 三種插入變體,針對主鍵/唯一鍵衝突有截然不同的處理邏輯,選擇得當能簡化應用層代碼。
INSERT INTO table_name (col1, col2) VALUES (val1, val2);
INSERT INTO table_name SELECT col1, col2 FROM other_table;
行為:若插入值導致主鍵或唯一索引衝突,直接拋出錯誤(Duplicate entry),事務回滾。
REPLACE INTO table_name (id, name) VALUES (1, 'new_name');
機制:
⚠ 陷阱:
DELETE + INSERT 兩個操作,導致 AUTO_INCREMENT 值變化、觸發器雙重觸發、外鍵級聯刪除等副作用。INSERT IGNORE INTO table_name (id, name) VALUES (1, 'ignored');
行為:遇到主鍵/唯一鍵衝突,不報錯、不插入、不回滾,僅產生 Warning,繼續執行後續語句。
適用場景:批量導入去重、日志寫入不重複、冪等性操作。
CREATE TABLE test (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO test (name) VALUES ('vein'), ('vein1'), ('vein2');
-- id 自增為 1,2,3
-- 1. 普通 INSERT 衝突
INSERT INTO test (id, name) VALUES (1, 'vein11');
-- ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
-- 2. INSERT IGNORE 靜默跳過
INSERT IGNORE INTO test (id, name) VALUES (1, 'vein11');
-- Query OK, 0 rows affected, 1 warning (0.00 sec)
-- 資料未變更,id=1 仍為 'vein'
-- 3. REPLACE INTO 覆蓋更新
REPLACE INTO test (id, name) VALUES (1, 'vein11');
-- Query OK, 2 rows affected (0.01 sec) ← 1 delete + 1 insert
-- 結果:id=1, name='vein11'
| 語句 | 衝突行為 | 適用場景 | 性能/副作用 |
|---|---|---|---|
| INSERT | 報錯中止 | 嚴格業務,必須感知衝突 | 最輕量,無副作用 |
| INSERT IGNORE | 靜默跳過 | 批量去重、冪等寫入、日志 | 輕量,但會產生 Warning |
| REPLACE | 刪舊插新 | 需全量覆蓋的「Upsert」語義 | 重,觸發 DELETE+INSERT,影響自增ID/觸發器/外鍵 |
現代替代方案:MySQL 8.0+ 推薦使用 INSERT ... ON DUPLICATE KEY UPDATE 實現真正的 Upsert,僅更新指定列,避免 REPLACE 的副作用。