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

賜我白日夢發表於2021-02-05

導讀

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專題,公眾號首發!持續更新中~

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

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

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

相關文章