Mysql on duplicate key update用法及優缺點


在實際應用中,經常碰到導入數據的功能,當導入的數據不存在時則進行添加,有修改時則進行更新,

  在剛碰到的時候,一般思路是將其實現分為兩塊,分別是判斷增加,判斷更新,后來發現在mysql中有ON DUPLICATE KEY UPDATE一步就可以完成(Mysql獨有的語法)。

ON DUPLICATE KEY UPDATE單個增加更新及批量增加更新的sql

在MySQL數據庫中,如果在insert語句后面帶上ON DUPLICATE KEY UPDATE 子句,而要插入的行與表中現有記錄的惟一索引或主鍵中產生重復值,那么就會發生舊行的更新;如果插入的行數據與現有表中記錄的唯一索引或者主鍵不重復,則執行新紀錄插入操作。

說通俗點就是數據庫中存在某個記錄時,執行這個語句會更新,而不存在這條記錄時,就會插入。

注意點:

  因為這是個插入語句,所以不能加where條件。

  如果是插入操作,受到影響行的值為1;如果更新操作,受到影響行的值為2;如果更新的數據和已有的數據一樣(就相當於沒變,所有值保持不變),受到影響的行的值為0。

該語句是基於唯一索引或主鍵使用,比如一個字段a被加上了unique index,並且表中已經存在了一條記錄值為1,

下面兩個語句會有相同的效果:

INSERT INTO table (a,b,c) VALUES (1,2,3)  
  ON DUPLICATE KEY UPDATE c=c+1;  
  
UPDATE table SET c=c+1 WHERE a=1;

ON DUPLICATE KEY UPDATE后面可以放多個字段,用英文逗號分割。

再現一個例子:

INSERT INTO table (a,b,c) VALUES (1,2,3),(4,5,6)  
      ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b); 

表中將更改(增加或修改)兩條記錄。

項目中數據的操作有時候會令人頭大,遇到一個需求:

需要將數據從A數據庫的a數據表同步到B數據庫的b數據表中(ab表結構相同,但不是主從關系。。。just同步過去)

第一次同步過去,b表為空,同步很簡單。

但是當a表中的某些數據更新且增加了新數據之后,再想讓兩個表同步就有些麻煩了。(如果把b表清空,重新同步,數據量過大的話耗費的時間太長,不是一個好辦法)

想着能不能按照時間段來做更新,這段時間內有新數據了,就插入數據,有數據更新了就更新數據。先說下我的思路:

步驟:

  1.首先我從a表取出某一時間段的數據(分段更新)

  2.往b表內放數據,根據主鍵判斷b表是否已經有此條記錄,沒有此數據則插入,有了記錄則對比數據是否一樣,一樣則不做更改,不一樣就做更新操作。

此時使用該語句可以滿足需要,但是要注意幾個問題:

  • 更新的內容中unique key或者primary key最好保證一個,不然不能保證語句執行正確(有任意一個unique key重復就會走更新,當然如果更新的語句中在表中也有重復校驗的字段,那么也不會更新成功而導致報錯,只有當該條語句沒有任何一個unique key重復才會插入新記錄);盡量不對存在多個唯一鍵的table使用該語句,避免可能導致數據錯亂。

  • 在有可能有並發事務執行的insert 語句情況下不使用該語句,可能導致產生death lock。

  • 如果數據表id是自動遞增的不建議使用該語句;id不連續,如果前面更新的比較多,新增的下一條會相應跳躍的更大。

  • 該語句是mysql獨有的語法,如果可能會設計到其他數據庫語言跨庫要謹慎使用。

產生death lock原理

insert ... on duplicate key 在執行時,innodb引擎會先判斷插入的行是否產生重復key錯誤,如果存在,在對該現有的行加上S(共享鎖)鎖,如果返回該行數據給mysql,然后mysql執行完duplicate后的update操作,然后對該記錄加上X(排他鎖),最后進行update寫入。

如果有兩個事務並發的執行同樣的語句,那么就會產生death lock,如:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM