Java面試題之MyBatis

MyBatis 是一個被廣泛應用的持久化框架。一個簡單的使用示例如下所示,先建立會話工廠,然後從會話工廠中開啟會話,透過 class 型別和配置生成 Mapper 介面的代理實現,最後使用 Mapper 進行持久化操作。

Java面試題之MyBatis

架構圖

1.MyBatis的優點

簡單易學:本身就很小且簡單。沒有任何第三方依賴,最簡單安裝只要兩個jar檔案+配置幾個sql對映檔案就可以了,易於學習,易於使用,透過文件和原始碼,可以比較完全的掌握它的設計思路和實現。

靈活:mybatis不會對應用程式或者資料庫的現有設計強加任何影響。sql寫在xml裡,便於統一管理和最佳化。透過sql語句可以滿足操作資料庫的所有需求。

解除sql與程式程式碼的耦合:透過提供DAO層,將業務邏輯和資料訪問邏輯分離,使系統的設計更清晰,更易維護,更易單元測試。sql和程式碼的分離,提高了可維護性。

提供xml標籤,支援編寫動態sql。

2.MyBatis框架的缺點:

SQL語句的編寫工作量較大,尤其是欄位多、關聯表多時,更是如此,對開發人員編寫SQL語句的功底有一定要求。

SQL語句依賴於資料庫,導致資料庫移植性差,不能隨意更換資料庫。

3.Mapper介面的工作原理是什麼?

Mapper介面的工作原理是JDK動態代理,Mybatis執行時會使用JDK動態代理為Dao介面生成代理proxy物件,代理物件proxy會攔截介面方法,轉而執行MappedStatement所代表的sql,然後將sql執行結果返回

4.Mybatis是如何將sql執行結果封裝為目標物件並返回的?都有哪些對映形式?

第一種是使用標籤,逐一定義資料庫列名和物件屬性名之間的對映關係。

第二種是使用sql列的別名功能,將列的別名書寫為物件屬性名。

有了列名與屬性名的對映關係後,Mybatis透過反射建立物件,同時使用反射給物件的屬性逐一賦值並返回,那些找不到對映關係的屬性,是無法完成賦值的。

5.Mybatis 是如何進行分頁的?分頁外掛的原理是什麼?

Mybatis 使用 RowBounds 物件進行分頁,它是針對 ResultSet 結果集執行的記憶體分頁,而非物理分頁。可以在 sql 內直接書寫帶有物理分頁的引數來完成物理分頁功能,也可以使用分頁外掛來完成物理分頁。

分頁外掛的基本原理是使用 Mybatis 提供的外掛介面,實現自定義外掛,在外掛的攔截方法內攔截待執行的 sql,然後重寫 sql,根據 dialect 方言,新增對應的物理分頁語句和物理分頁引數。

6.Mybatis 是否支援延遲載入?如果支援,它的實現原理是什麼?

Mybatis 僅支援 association 關聯物件和 collection 關聯集合物件的延遲加 載,association 指的就是一對一,collection 指的就是一對多查詢。在 Mybatis 配置檔案中,可以配置是否啟用延遲載入 lazyLoadingEnabled=true|false。

它的原理是,使用 CGLIB 建立目標物件的代理物件,當呼叫目標方法時,進入攔截器方法,比如呼叫 a。getB()。getName(),攔截器 invoke()方法發現 a。getB()是null 值,那麼就會單獨傳送事先儲存好的查詢關聯 B 物件的 sql,把 B 查詢上來,然後呼叫 a。setB(b),於是 a 的物件 b 屬性就有值了,接著完成 a。getB()。getName()方法的呼叫。這就是延遲載入的基本原理。

當然了,不光是 Mybatis,幾乎所有的包括 Hibernate,支援延遲載入的原理都是一樣的。

7.Mybatis 的一級、二級快取?

1)一級快取: 基於 PerpetualCache 的 HashMap 本地快取,其儲存作用域為 Session,當 Session flush 或 close 之後,該 Session 中的所有 Cache 就 將清空,預設開啟一級快取。

2)二級快取與一級快取其機制相同,預設也是採用 PerpetualCache,HashMap儲存,不同在於其儲存作用域為 Mapper(Namespace),並且可自定義儲存源,如 Ehcache。預設不開啟二級快取,要開啟二級快取,使用二級快取屬性類需要實現 Serializable 序列化介面(可用來儲存物件的狀態),可在它的對映檔案中配置;

3)對於快取資料更新機制,當某一個作用域(一級快取 Session/二級快取Namespaces)的進行了 C/U/D 操作後,預設該作用域下所有 select 中的快取將被 clear。

8.簡述 Mybatis 的外掛執行原理,以及如何編寫一個外掛

Mybatis 僅可以編寫針對 ParameterHandler、ResultSetHandler、StatementHandler、Executor 這 4 種介面的外掛,Mybatis 使用 JDK 的動態代理,為需要攔截的介面生成代理物件以實現介面方法攔截功能,每當執行這 4 種介面物件的方法時,就會進入攔截方法,具體就是 InvocationHandler 的 invoke()方法,當然,只會攔截那些你指定需要攔截的方法。

編寫外掛:實現 Mybatis 的 Interceptor 介面並複寫 intercept()方法,然後在給外掛編寫註解,指定要攔截哪一個介面的哪些方法即可,記住,別忘了在配置檔案中配置你編寫的外掛。