insertOrUpdate在我們日常使用中比較常見,那麼它是如何實現的呢,不知道大家有沒有考慮過呢?
在MySQL中,可採用INSERT INTO ... ON DUPLICATE KEY UPDATE
語句實現insertOrUpdate功能。
值得留意的是,在出現重複鍵時,會在先前索引值和當前值之間新增臨時鍵鎖,這可能導致死鎖。
若要使用INSERT INTO ... ON DUPLICATE KEY UPDATE語句,需滿足以下條件:
表必須具有主鍵或唯一索引;
插入的資料必須包含主鍵或唯一索引列;
主鍵或唯一索引列的值不能為NULL。
舉個例子:
設想有一張student表,包括id、name和age三列,其中id是主鍵。現在要插入一條資料,若該資料的主鍵已存在,則更新該資料的姓名和年齡,否則插入該資料。
INSERT INTO student (id, name, age) VALUES (1, 'Paidaxing', 20) ON DUPLICATE KEY UPDATE name='Paidaxing', age=18;
底層實現
使用INSERT INTO ... ON DUPLICATE KEY UPDATE
語句,如果資料庫中已存在具有相同唯一索引或主鍵的記錄,則更新該記錄。其底層原理和執行流程如下:
檢查唯一索引或主鍵:執行
INSERT INTO ... ON DUPLICATE KEY UPDATE
語句時,資料庫首先嚐試插入新行。在此過程中,資料庫會檢查表中是否存在與新插入行具有相同的唯一索引或主鍵的記錄。衝突處理:如果不存在衝突的唯一索引或主鍵,新行將被正常插入。如果存在衝突,即發現重複的唯一索引或主鍵值,資料庫將不會插入新行,而是轉而執行更新操作。
執行更新:在檢測到唯一索引或主鍵的衝突後,資料庫將根據
ON DUPLICATE KEY UPDATE
後面指定的列和值來更新已存在的記錄。這裏可以指定一個或多個列進行更新,並且可以使用VALUES函式引用原本嘗試插入的值。
相似SQL
除了INSERT INTO ... ON DUPLICATE KEY UPDATE之外,還有一些類似的SQL語句,比如:
REPLACE INTO:如果存在唯一索引衝突,則先刪除舊記錄,再插入新記錄。
INSERT IGNORE INTO:如果唯一索引衝突,則忽略該條插入操作,不報錯。
淺談主鍵跳躍
在MySQL中使用INSERT ON DUPLICATE KEY UPDATE語句時,如果插入操作失敗(因為主鍵或唯一鍵衝突),而執行了更新操作,確實會導致自增主鍵計數器增加,即使沒有實際插入新記錄。
這是因為MySQL在嘗試插入新記錄時,會先分配一個新的自增主鍵值,無論後續是插入成功還是執行更新操作,這個主鍵值都已經被分配並且會增加。
例如,假設有一個表test定義如下:
CREATE TABLE test ( id INT AUTO_INCREMENT PRIMARY KEY, value VARCHAR(255), UNIQUE KEY unique_value (value) );
然後執行以下語句:
INSERT INTO test (value) VALUES ('a') ON DUPLICATE KEY UPDATE value = 'a';
再執行一次:
此時,由於value列存在唯一鍵約束,並且已經存在一條記錄value='a',所以不會插入新記錄,而是會執行更新操作。但即便如此,自增主鍵id的計數器依然會增加。
然後再插入一條新的記錄:
這意味著下一次插入新記錄時,自增主鍵的值會比之前增加,即2已經被用過了,雖然沒插入成功,但是新的記錄就直接用3了。