當前位置: 妍妍網 > 碼農

面試官:MyBatis中resultMap的實作原理是什麽?徹底懵逼了。。

2024-04-19碼農

嗨,你好呀,我是哪咤。

面試的時候,被問到 「MyBatis中resultMap的實作原理是什麽?」

我的第一反應就是, resultMap不就是進行自動對映的嘛!還有原理?

MyBatis支持自動對映,可以根據查詢結果的列名和Java物件的內容名自動匹配。在使用自動對映時,結果集中的列名會與Java物件的內容名進行匹配,無需在Mapper XML檔中手動配置對映關系,簡化了開發。

透過 標簽配置查詢結果集與Java物件之間的對映關系,或者使用 指定查詢結果對映到的Java物件型別。在insert、update、delete等操作中,也會使用

標簽配置參數與SQL語句中的占位符之間的對映關系。

透過 TypeHandler 實作Java型別和資料庫欄位型別之間的轉換。MyBatis提供了一些內建的TypeHandler,同時也允許使用者自訂TypeHandler來處理特定的轉換邏輯,確保資料庫欄位的數據型別正確地對映到Java物件的內容型別。

MyBatis的TypeHandler是一個介面,用於處理Java型別與JDBC型別之間的轉換。

當執行SQL語句時,如果語句中包含了參數占位符(如#{param}),MyBatis會使用TypeHandler將Java方法參數的型別轉換為JDBC可以理解的SQL型別,以便在資料庫操作中使用。

查詢資料庫後,MyBatis會使用TypeHandler將結果集中的數據從SQL型別轉換為Java物件的內容型別,這樣就能夠將查詢結果對映到Java物件上。

小結一下:

TypeHandler主要用於處理單個內容的對映,而resultMap則用於處理整個結果集的對映。

TypeHandler 是用於處理單個Java物件內容與資料庫欄位之間的對映。它負責將Java物件的內容值轉換為JDBC可以理解的型別,以及將查詢結果從JDBC型別轉換回Java物件的內容型別。這種轉換是基於Java型別和JDBC型別之間的對映關系來實作的。

resultMap 是用來定義如何將整個查詢結果集對映到Java物件。 它提供了更復雜的對映能力,允許開發者自訂如何將資料庫列名對映到Java物件的內容上,適用於復雜的數據結構,如關聯查詢的結果。

再分享幾道關於MyBatis的常見問題,作為 的補充。

1、當查詢結果集包含多個表的聯合查詢時,如何使用resultMap將這些結果對映到Java物件?

在Mapper XML檔中定義resultMap,將查詢結果對映到Java物件上。可以使用 元素來處理關聯查詢的結果,使用 元素來處理集合型別的內容。

<resultMapid="userOrderResult"type="com.example.UserOrder">
<idproperty="id"column="user_id"/>
<resultproperty="username"column="username"/>
<resultproperty="email"column="email"/>
<collectionproperty="orders"ofType="com.example.Order">
<idproperty="orderId"column="order_id"/>
<resultproperty="productName"column="product_name"/>
<resultproperty="price"column="price"/>
</collection>
</resultMap>

在執行查詢操作時,參照這個resultMap

<selectid="getUserOrders"resultMap="userOrderResult">
SELECT u.id as user_id, u.username, u.email, o.id as order_id, o.product_name, o.price
FROM user u
LEFT JOIN order o ON u.id = o.user_id
WHERE u.id = #{userId}
</select>

這樣,MyBatis就會根據定義的resultMap將查詢結果對映到Java物件上,並將這些物件返回給呼叫者。

2、如何使用MyBatis的resultMap進行分頁查詢?

在Mapper XML檔中定義resultMap,將查詢結果對映到Java物件上。

<resultMapid="userResult"type="com.example.User">
<idproperty="id"column="id"/>
<resultproperty="username"column="username"/>
<resultproperty="email"column="email"/>
</resultMap>

在執行查詢操作時,參照這個resultMap。

<selectid="getUsersByPage"resultMap="userResult">
SELECT * FROM user LIMIT #{offset}, #{pageSize}
</select>

其中,#{offset}表示偏移量,即從第幾條記錄開始查詢;#{pageSize}表示每頁顯示的記錄數。

最後,在呼叫該查詢方法時,傳入相應的參數即可實作分頁查詢。例如:

List<User> users = userMapper.getUsersByPage(010); // 獲取前10條記錄

3、resultMap是如何提高整體效能的?

(1)可重用性

定義好的 可以在多個查詢語句中重復使用,提高了程式碼的復用性和維護性。而且,MyBatis還提供了繼承 的功能,進一步增加了配置的靈活性,使配置的重復利用更加便捷。

(2)二級緩存

可以幫助 MyBatis 辨識並利用二級緩存(如與資料庫查詢結果的緩存),從而提高系統效能,減少對資料庫的頻繁存取。

(3)減少欄位對映錯誤

透過明確定義 ,開發人員可以準確地指定查詢結果集中的每列數據應該對映到哪個 Java 物件的內容上。這有助於避免因為欄位名字或順序變化而導致的對映錯誤,從而減少偵錯和排查錯誤的時間,提高開發效率。

4、MyBatis是如何實作PreparedStatement的?

MyBatis透過使用JDBC的PreparedStatement來實作預編譯的SQL語句。

  1. 獲取資料庫連線 :MyBatis首先需要獲取一個資料庫連線物件;

  2. 準備SQL語句 :MyBatis會將使用者傳入的參數(如#{xxx})與SQL語句中的占位符(即"?")進行繫結。這個過程稱為預編譯,它允許MyBatis將參數安全地插入到SQL語句中,防止了SQL資料隱碼攻擊。

  3. 建立PreparedStatement :MyBatis在執行SQL語句時,會為每次查詢建立一個新的PreparedStatement物件。這個物件是JDBC API的一部份,它表示一種預編譯的SQL語句,可以提高執行效率和安全性。

  4. 執行SQL語句 :MyBatis使用PreparedStatement物件的executeQuery方法來執行SQL查詢,並返回結果集。

  5. 處理結果集 :MyBatis將結果集轉換為Java物件,這個過程可以透過配置的resultMap來完成,它可以將資料庫的列對映到Java物件的內容上。

  6. 資源釋放 :執行完畢後,MyBatis會負責關閉PreparedStatement和Connection等資源,以釋放資料庫連線。

5、MyBatis如何關閉資料庫連線?

(1)連線池

MyBatis通常與連線池一起使用,連線池負責管理資料庫連線的建立、分配和釋放。當MyBatis需要執行SQL語句時,它會從連線池中獲取一個可用的連線,而不是直接建立新的連線。

(2)事務管理

MyBatis提供了事務管理的功能,它會根據配置的事務策略(如送出或回滾)來處理資料庫連線的關閉。如果事務送出成功,連線會被返回到連線池中;如果事務回滾,連線可能會被關閉。

(3)資源清理

MyBatis在執行SQL語句後,會負責關閉PreparedStatement和ResultSet等資源,以釋放資料庫連線。這可以透過配置的資源清理策略來實作,例如使用try-with-resources語句或顯式呼叫close方法。

(4)配置參數

MyBatis的配置參數也會影響資料庫連線的關閉行為。例如,可以設定是否自動送出事務、是否緩存查詢結果等,這些都會影響連線的關閉時機和方式。

(5)例外處理

MyBatis在執行過程中可能會遇到各種異常,如SQL錯誤、網路中斷等。在這些情況下,MyBatis會根據異常型別來決定如何處理資料庫連線,例如重試、回滾或關閉連線。

(6)外掛程式機制

MyBatis還支持外掛程式機制,允許開發者自訂外掛程式來攔截和處理資料庫操作。透過外掛程式,可以實作更復雜的資源管理和例外處理邏輯,例如自訂連線池、監控資料庫效能等。

6、MyBatis如何管理連線池的?

MyBatis作為一個ORM框架,它本身並不直接管理資料庫連線,而是透過配置資料來源來實作。

(1)內建連線池

當在MyBatis配置檔中設定 時,MyBatis會使用內建的連線池。這個連線池是在MyBatis內部實作的,它會在啟動時初始化一定數量的資料庫連線,並在需要時提供給MyBatis使用。

(2)第三方連線池

如果需要使用第三方的資料庫連線池,如DBCP、C3P0、Druid或Hikari等,可以在MyBatis的配置中進行相應的設定。這些連線池通常提供更好的效能和更豐富的功能,如連線監控和統計等。

(3)UnpooledDataSource

如果不希望使用連線池,可以將資料來源型別設定為UNPOOLED。

這種情況下,MyBatis會為每次查詢建立一個新的資料庫連線,並在查詢結束後關閉該連線。

不推薦使用。

(4)事務管理

MyBatis的事務管理也是連線池管理的一部份。當使用事務時,MyBatis會根據事務的開始和結束來控制連線的獲取和釋放。如果事務成功送出,連線會被返回到連線池中;如果事務回滾,連線可能會被關閉。

(5)資源清理

MyBatis在執行SQL語句後,會負責關閉PreparedStatement和ResultSet等資源,以釋放資料庫連線。這可以透過配置的資源清理策略來實作,例如使用try-with-resources語句或顯式呼叫close方法。

7、如何理解MyBatis中的資源清理策略?

(1)更新數據時清除緩存

當執行數據更新操作(如INSERT、UPDATE或DELETE)時,應確保相關的緩存被及時清除或更新,以避免臟讀或數據不一致的情況發生。

(2)合理配置緩存大小

為了避免緩存占用過多記憶體,應根據套用的需求和伺服器的效能來合理配置緩存的大小和清除策略。

(3)處理緩存並行問題

在並行環境下,需要特別註意緩存可能引起的問題,如臟讀或數據不一致。可以透過配置事務隔離級別或者使用樂觀鎖等機制來減少並行問題的發生。

(4)關閉自動送出

為了防止每次執行SQL語句後都自動送出事務,導致頻繁地開啟和關閉資料庫連線,可以在MyBatis的配置中關閉自動送出功能。

(5)使用合適的資源清理策略

MyBatis提供了不同的資源清理策略,如基於時間、基於空間或基於計數等。選擇合適的策略可以幫助有效地管理資源,避免資源泄露。

8、如何在MyBatis中配置資源清理策略?

(1)資料庫連線資源管理

MyBatis本身不提供連線池,但可以與第三方連線池整合,比如常用的 c3p0、Druid 等。透過配置連線池的參數,可以控制連線的獲取和釋放、最大連線數、空閑連線超時等。

(2)緩存資源管理

MyBatis 支持二級緩存,可以在 標簽中配置二級緩存的內容,包括緩存重新整理間隔、緩存過期時間等。

<!-- 開啟二級緩存 -->
<cacheeviction="FIFO"flushInterval="60000"size="512"/>

(3)開啟自動送出

設定在執行查詢語句後自動送出事務,這樣可以及時釋放資源。

<settingname="autoCommit"value="true"/>

(4)使用SqlSessionFactoryBuilder建造者模式

使用 SqlSessionFactoryBuilder 來建立 SqlSessionFactory,在建立完成後對其進行立即銷毀操作,這樣可以釋放資源並避免資源泄露。

SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader);
// 使用 factory 建立 SqlSession
factory.close();

(5)手動釋放資源

在使用完畢後,顯式呼叫相關資源的關閉方法,如關閉 SqlSession、清理緩存等。

SqlSession session = sqlSessionFactory.openSession();
// 執行資料庫操作
session.close();

今天就到這裏啦,明天見~

謝謝你那麽有耐心,看到了這裏,共勉~

往期文章: