前言
??在日常的數(shù)據(jù)庫操作中,我們經(jīng)常會(huì)遇到這樣的場景:“如果數(shù)據(jù)存在,就更新它;如果不存在,就插入一條新的”。這種模式通常被稱為 “Upsert”(Update + Insert)。在 MySQL 中,實(shí)現(xiàn) Upsert 最優(yōu)雅、最高效的方式之一就是使用 ON DUPLICATE KEY UPDATE 語法。
一、基本概念
1、什么是 ON DUPLICATE KEY UPDATE?
??ON DUPLICATE KEY UPDATE是 MySQL 特有的一種 INSERT 語句擴(kuò)展,當(dāng)執(zhí)行 INSERT 操作時(shí),如果插入的數(shù)據(jù)與表中已有數(shù)據(jù)的主鍵(PRIMARY KEY)或唯一索引(UNIQUE INDEX)發(fā)生沖突(即要插入的值與已有記錄的主鍵或唯一索引值相同),則不執(zhí)行插入操作,而是轉(zhuǎn)而執(zhí)行 UPDATE 操作,更新已存在的記錄。
2、工作原理
嘗試插入:MySQL 首先嘗試按照正常的 INSERT 語句插入新記錄
檢查沖突:在插入前,MySQL 會(huì)檢查是否存在與待插入數(shù)據(jù)主鍵或唯一索引沖突的記錄
沖突處理:
如果沒有沖突:正常插入新記錄
如果有沖突:不插入新記錄,而是根據(jù) ON DUPLICATE KEY UPDATE子句更新已存在的記錄
3、基本語法
基本語法格式如下:
INSERT INTO table_name (column1, column2, ..., columnN)
VALUES (value1, value2, ..., valueN)
ON DUPLICATE KEY UPDATE
column1 = value1,
column2 = value2,
...;
更常用的寫法是使用 VALUES() 函數(shù)來引用原本打算插入的值:
INSERT INTO table_name (column1, column2, ..., columnN)
VALUES (value1, value2, ..., valueN)
ON DUPLICATE KEY UPDATE
column1 = VALUES(column1),
column2 = VALUES(column2),
...;
觸發(fā)條件:只有當(dāng)插入操作違反了 主鍵(PRIMARY KEY) 或 唯一索引(UNIQUE INDEX) 約束時(shí),UPDATE 部分才會(huì)被執(zhí)行
二、使用場景
1、計(jì)數(shù)器更新
INSERT INTO article_views (article_id, view_count)
VALUES (123, 1)
ON DUPLICATE KEY UPDATE
view_count = view_count + 1;
2、配置項(xiàng)更新
INSERT INTO system_config (config_key, config_value, last_updated)
VALUES ('site_title', 'My Website', NOW())
ON DUPLICATE KEY UPDATE
config_value = VALUES(config_value), last_updated = NOW();
3、購物車商品更新
INSERT INTO shopping_cart (user_id, product_id, quantity)
VALUES (123, 456, 2)
ON DUPLICATE KEY UPDATE
quantity = quantity + VALUES(quantity),
added_at = CURRENT_TIMESTAMP;
必須添加主鍵或唯一索引,否則ON DUPLICATE KEY UPDATE將不會(huì)觸發(fā),語句會(huì)正常執(zhí)行插入操作(如果無其他錯(cuò)誤)
三、高級用法
1、條件更新
在 ON DUPLICATE KEY UPDATE子句中使用條件表達(dá)式
-- 這個(gè)例子只在新的價(jià)格更低時(shí)才更新價(jià)格
INSERT INTO products (product_id, price, last_updated)
VALUES (101, 99.99, NOW())
ON DUPLICATE KEY UPDATE
price = IF(VALUES(price) < price, VALUES(price), price),
last_updated = NOW();
2、多表關(guān)聯(lián)
雖然不能直接在 ON DUPLICATE KEY UPDATE中使用多表,但可以結(jié)合子查詢
INSERT INTO user_stats (user_id, login_count)
SELECT 123, 1 FROM dual
WHERE NOT EXISTS (SELECT 1 FROM users WHERE id = 123)
ON DUPLICATE KEY UPDATE
login_count = login_count + 1;
3、批量操作優(yōu)化
對于大量數(shù)據(jù)的批量插入/更新,考慮以下優(yōu)化
INSERT INTO log_entries (user_id, action, timestamp)
VALUES
(1, 'login', NOW()),
(2, 'view', NOW()),
(3, 'purchase', NOW())
ON DUPLICATE KEY UPDATE
action = VALUES(action),
timestamp = VALUES(timestamp);
當(dāng)表有多個(gè)唯一約束時(shí),任何唯一鍵沖突都會(huì)觸發(fā)UPDATE
四、其他處理沖突的方案
1、REPLACE INTO
實(shí)際上是先DELETE再INSERT,主鍵會(huì)有變化
REPLACE INTO users (email, name, login_count)
VALUES ('test@example.com', 'Test User', 1);
2、INSERT IGNORE
沖突時(shí)直接忽略,不更新
INSERT IGNORE INTO users (email, name)
VALUES ('test@example.com', 'Test User');
參考文章:原文鏈接?
該文章在 2025/10/27 16:44:02 編輯過