一個小小的批量插入,被面試官追問了六次
嗨,你好呀,我是哪吒。
面試經常被問到“MyBatis批量入庫時,xml的foreach和java的foreach,性能上有什么區別?”。
首先需要明確一點,優先使用批量插入,而不是在Java中通過循環單條插入。
很多小伙伴都知道這個結論,但是,為啥?很少有人能說出個所以然來。
就算我不知道,你也不能反反復復問我“同一個問題”吧?
1、MyBatis批量入庫時,xml的foreach和java的foreach,性能上有什么區別?
批量入庫時,如果通過Java循環語句一條一條入庫,每一條SQL都需要涉及到一次數據庫的操作,包括網絡IO以及磁盤IO,可想而知,這個效率是非常低下的。
xml中使用foreach的方式會一次性發送給數據庫執行,只需要進行一次網絡IO,提高了效率。
但是,xml中的foreach可能會導致內存溢出OOM問題,因為它會一次性將所有數據加載到內存中。而java中的foreach可以有效避免這個問題,因為它會分批次處理數據,每次只處理一部分數據,從而減少內存的使用。
如果操作比較復雜,例如需要進行復雜的計算或者轉換,那么使用java中的foreach可能會更快,因為它可以直接利用java的強大功能,而不需要通過xml進行轉換。
孰重孰輕,就需要面試官自己拿捏了~
2、在MyBatis中,對于<foreach>標簽的使用,通常有幾種常見的優化方法?
比如避免一次性傳遞過大的數據集合到foreach中,可以通過分批次處理數據或者在業務層先進行數據過濾和篩選。
預編譯SQL語句、優化SQL語句,減少foreach編譯的工作量。
對于重復執行的SQL語句,可以利用mybatis的緩存機制來減少數據庫的訪問次數。
對于關聯查詢,可以考慮使用mybatis的懶加載特性,延遲加載關聯數據,減少一次性加載的數據量。
3、MyBatis foreach批量插入會有什么問題?
foreach在處理大量數據時會消耗大量內存。因為foreach需要將所有要插入的數據加載到內存中,如果數據量過大,可能會導致內存溢出。
有些數據庫對單條SQL語句中可以插入的數據量有限制。如果超過這個限制,foreach生成的批量插入語句將無法執行。
使用foreach進行批量插入時,需要注意事務的管理。如果部分插入失敗,可能需要進行回滾操作。
foreach會使SQL語句變得復雜,可能影響代碼的可讀性和可維護性。
4、當使用foreach進行批量插入時,如何處理可能出現的事務問題?內存不足怎么辦?
本質上這兩個是一個問題,就是SQL執行慢,一次性執行SQL數量大的問題。
大多數數據庫都提供了事務管理功能,可以確保一組操作要么全部成功,要么全部失敗。在執行批量插入操作前,開始一個數據庫事務,如果所有插入操作都成功,則提交事務;如果有任何一條插入操作失敗,則回滾事務。
如果一次插入大量數據,可以考慮分批插入。這樣,即使某一批插入失敗,也不會影響到其他批次的插入。
優化foreach生成的SQL語句,避免因SQL語句過長或過于復雜而導致的問題。
比如MySQL的INSERT INTO ... VALUES語法 通常比使用foreach進行批量插入更高效,也更可靠。
5、MyBati foreach批量插入時如何處理死鎖問題?
當使用MyBatis的foreach進行批量插入時,可能會遇到死鎖問題。這主要是因為多個事務同時嘗試獲取相同的資源(如數據庫的行或表),并且每個事務都在等待其他事務釋放資源,從而導致了死鎖。
(1)優化SQL語句
確保SQL語句盡可能高效,避免不必要的全表掃描或復雜的聯接操作,這可以減少事務持有鎖的時間,從而降低死鎖的可能性。
不管遇到什么問題,你就回答優化SQL,基本上都沒毛病。
(2)設置鎖超時
為事務設置一個合理的鎖超時時間,這樣即使發生死鎖,也不會導致系統長時間無響應。
(3)使用樂觀鎖
樂觀鎖是一種非阻塞性鎖,它假設多個事務在同一時間不會沖突,因此不會像悲觀鎖那樣在每次訪問數據時都加鎖。樂觀鎖通常用于讀取頻繁、寫入較少的場景。
(4)分批插入
如果一次插入大量數據,可以考慮分批插入。這樣,即使某一批插入失敗,也不會影響到其他批次的插入。
(5)調整事務隔離級別
較低的隔離級別(如READ UNCOMMITTED)可能會減少死鎖的發生,但可能會導致其他問題,如臟讀或不可重復讀。
6、mybatis foreach批量插入時如果數據庫連接池耗盡,如何處理?
(1)增加最大連接數
數據庫連接池耗盡了,增加最大連接數,這個回答,沒毛病。
(2)優化SQL語句
減少每個連接的使用時間,從而減少連接池耗盡的可能性。
萬變不離其宗,優化SQL,沒毛病。
(3)分批插入
避免一次性占用過多的連接,從而減少連接池耗盡的可能性。
(4)調整事務隔離級別
降低事務隔離級別可以減少每個事務持有連接的時間,從而減少連接池耗盡的可能性。但需要注意,較低的事務隔離級別可能會導致其他問題,如臟讀或不可重復讀。
(5)使用更高效的批量插入方法
比如MySQL的INSERT INTO ... VALUES語法。這些方法通常比使用foreach進行批量插入更高效,也更節省連接資源。
感覺每道題的答案都是一樣呢?這就對嘍,數據庫連接池耗盡,本質問題不就是入庫的速度太慢了嘛。
(6)定期檢查并關閉空閑時間過長的連接,以釋放連接資源。
就前面的幾個問題,做一個小總結,你會發現,它們的回答大差不差。
通過現象看本質,批量插入會有什么問題?事務問題?內存不足怎么辦?如何處理死鎖問題?數據庫連接池耗盡,如何處理?
這些問題的本質都是因為SQL執行慢,一次性SQL數據量太大,事務提交太慢導致的。
回答的核心都是:如何降低單次事務時間?
- 優化SQL語句
- 分批插入
- 調整事務隔離級別
- 使用更高效的批量插入方法