大型翻車現場:如何實現記錄存在的話就更新,如果記錄不存在的話就插入。很簡單、但是很實用


導讀

Hi,大家好!我是白日夢!本文是MySQL專題的第 26 篇。

下文還是白日夢以自導自演的方式,圍繞“如何實現記錄存在的話就更新,如果記錄不存在的話就插入。”展開本話題。看看你能抗到第幾問吧

換一種寫作風格,自導自演面試現場!感覺這樣還是比較有趣的,歡迎大家訂閱我的MySQL專題,公眾號首發!持續更新中~

點擊閱讀原文,格式會好看一點哦~

點擊閱讀原文,格式會好看一點哦~

點擊閱讀原文,格式會好看一點哦~

歡迎關注白日夢,公眾號首發!持續連載中

1
好!我們開始吧! 
                              

Hi同學,前面表現的不錯哦。關於MySQL的基礎掌握的還可以,現在有時間繼續嗎?


嗯,有時間!



白日夢有話說 是啊,那能掛嗎? 這個專題還有好多文章沒寫完呢!掛了怎么往下寫?


那我們繼續面吧。出一道場景題:現在我的業務中有這樣的需求:如果目標記錄存在的話我就更新它,如果記錄不存在的話我就插入。說說看你知道哪些實現方式吧!


嗯,比如我可以像下面這樣做


這種方式。

// 偽代碼user=User.FindById(1)if user == null{  user.Insert()}else{  user.Update()}



嗯,這確實可以。但是你有更好的方式嗎?看你代碼,每次都是先查詢、再更新/寫入。至少都會和MySQL發生兩次網絡交互哦!

嗯,還可以像下面這樣,我先嘗試更新,如果沒有這條記錄的話,更新函數返回的影響行數就是0。於是我根據這個影響行數去判斷,當影響行數為0時說明數據庫中沒有這條記錄。於是我就寫入。



通過這種方式和MySQL之間的網絡請求次數就有可能降低成1。

// 偽代碼effectRows=User.UpdateById(1)if effectRows >0 {  user.Insert()}



我看未必吧!並且你這代碼存在安全隱患啊!比如遇到這種情況:user實例中的信息和數據庫中的記錄完全一致。然后你拿着user中的信息去更新數據庫中的信息。實際上就沒有發生任何改變。也就是說,你的代碼中的UpdateById(1)的返回值是0!



然后你的代碼進入else中,很顯然id=1的行已經存在了,你還執行insert xxx id = 1,這肯定會報錯說:主鍵沖突啊!


我靠!大佬說的對啊!按你這么說,這確實是個風險。即使每次去更新的時候攜帶上最新的時間戳也無法保證它一定不會進入到else中!




嗯,對的。我們繼續這個話題,你還知道其他的實現方式嗎?我提示你一下:你有沒有使用過 insert ignore into 語句?


嗯嗯,使用過,insert ignore into的作用是:如果記錄存在了就忽略本次ignore本次插入。如果記錄不存在就寫入。



關於insert ignore into的實戰可以看這個示例


Step1:創建庫表


Step2:正常寫入一條數據


Step3:使用insert ignore 重復寫入和上一條SQL完全一種的數據


Step4:使用insert ignore寫入一條新的數據,會發現可以寫入成功。


Step5:使用insert ignore寫入,測試一下如果想寫入的數據的id(唯一key)已經在表中存在了,其他的非唯一鍵數據不一樣。你會發現:也不能重復寫入




嗯,通過你的實驗可以看出:insert ignore into的功能是:如果數據已經存在了就忽略本次寫入,如果數據不存在就insert。通過上面你做的實驗也可以看出它判斷是否可以寫入的標准是:唯一鍵不能重復。


只要你想寫入的數據和現有的唯一鍵沖突了,最終就不會將你的數據落庫。


嗯嗯,這么看來insert ignore into 並不能滿足我們的業務需求。不過我還了解 replace into




嗯!那你說說這個replace 吧!


,replace into的作用是:如果數據已經存在了我就更新。如果數據不存在就更寫入。


而判斷數據是否已經存在的標准依然是:判斷唯一鍵是否重復。




嗯,繼續。


嗯嗯,可以看下面的這個例子:


Step1:如果數據不存在replace 可以將數據寫入進去


Step2:如果數據存在replace 可以使用新數據替換舊數據。


而且這個替換還是全量替換:




嗯,很好,使用replace into 確實能做到一次網絡請求就實現我們的業務需求。



其實我還知道另一種實現方式:也可以通過一次網絡請求實現咱們的業務需求。




哦?你說說看!


使用 on duplicate key update也可以實現,如果記錄存在就更新,如果記錄不存在就插入。



關於: on duplicate key update 可以看這個例子:


Step1: 如果已經存在了,就更新。


Step2:如果不存在就寫入

(上面兩圖中的ignore不影響)




白日夢補充: 下圖截自MySQL官網,有一些值得我們注意的點:


其實你想一下,通常情況下,我們業務代碼中的insert語句是沒有指定主鍵的id等於多少的。因為這個主鍵會自己增加。官網中有描述: 如果你每次使用on duplicate key update進行更新時(注意是更新而不是插入),MySQL也會讓last_insert_id變大。這就會出現id不連續增長的現象。

你可以看這個示例,我復現了一下主鍵id不連續增長的現象。


Step1:  創建數據表


Step2 使用 on duplicate key update 寫入一條記錄。此時LAST_INSERT_ID為1


Step3:  重復執行,使用 on duplicate key update 將shanghai更新成beijing。此時LAST_INSERT_ID同樣會+1,變成2。


Step4:  驗收結果的時刻來了。使用 on duplicate key update 插入name = hunan的行,注意觀察行的主鍵id為3。




小伙子可以的!整體感覺還不錯。


不久會給你安排下一面


我沒有問題了,你有什么想問我的嗎?


感謝大佬,歡迎關注我,點贊、在讀、打賞、轉發馬上安排上!



推薦閱讀

  1. MySQL的修仙之路,圖文談談如何學MySQL、如何進階!(已發布)
  2. 面前突擊!33道數據庫高頻面試題,你值得擁有!(已發布)
  3. 大家常說的基數是什么?(已發布)
  4. 講講什么是慢查!如何監控?如何排查?(已發布)
  5. 對NotNull字段插入Null值有啥現象?(已發布)
  6. 能談談 date、datetime、time、timestamp、year的區別嗎?(已發布)
  7. 了解數據庫的查詢緩存和BufferPool嗎?談談看!(已發布)
  8. 你知道數據庫緩沖池中的LRU-List嗎?(已發布)
  9. 談談數據庫緩沖池中的Free-List?(已發布)
  10. 談談數據庫緩沖池中的Flush-List?(已發布)
  11. 了解臟頁刷回磁盤的時機嗎?(已發布)
  12. 用十一張圖講清楚,當你CRUD時BufferPool中發生了什么!以及BufferPool的優化!(已發布)
  13. 聽說過表空間沒?什么是表空間?什么是數據表?(已發布)
  14. 談談MySQL的:數據區、數據段、數據頁、數據頁究竟長什么樣?了解數據頁分裂嗎?談談看!(已發布)
  15. 談談MySQL的行記錄是什么?長啥樣?(已發布)
  16. 了解MySQL的行溢出機制嗎?(已發布)
  17. 說說fsync這個系統調用吧! (已發布)
  18. 簡述undo log、truncate、以及undo log如何幫你回滾事物! (已發布)
  19. 我勸!這位年輕人不講MVCC,耗子尾汁! (已發布)
  20. MySQL的崩潰恢復到底是怎么回事? (已發布)
  21. MySQL的binlog有啥用?誰寫的?在哪里?怎么配置 (已發布)
  22. MySQL的bin log的寫入機制 (已發布)
  23. 刪庫后!除了跑路還能干什么?(已發布)
  24. 自導自演的面試現場,趣學數據庫的10種文件(已發布)
  25. 大型面試現場:一條update sql執行都經歷什么?(已發布)
  26. 大型翻車現場:如何實現記錄存在的話就更新,如果記錄不存在的話就插入。(已發布)

最后,歡迎關注白日夢的公號哦~

換一種寫作風格,自導自演面試現場!感覺這樣還是比較有趣的,歡迎大家訂閱我的MySQL專題,公眾號首發!持續更新中~

點擊閱讀原文,格式會好看一點哦~

點擊閱讀原文,格式會好看一點哦~

點擊閱讀原文,格式會好看一點哦~


免責聲明!

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



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