1. 程式人生 > 其它 >Java 面試題-Hibernate、MyBatis

Java 面試題-Hibernate、MyBatis

1.為什麼要使用 Hibernate?
  • Hibernate是對 jdbc 的封裝,大大簡化了資料訪問層的繁瑣的重複性程式碼。
  • Hibernate是一個優秀的 ORM 實現,很多程度上簡化了 DAO 層的編碼功能。
  • 可以很方便的進行資料庫的移植工作。
  • 提供了快取機制,是程式執行更改的高效。
2.什麼是 ORM 框架?

    ORM(Object Relation Mapping)物件關係對映,是把資料庫中的關係資料對映成為程式中的物件。

    使用 ORM 的優點:提高了開發效率降低了開發成本、開發更簡單更物件化、可移植更強。

3.Hibernate 中如何在控制檯檢視列印的 SQL 語句?

    在 Config 裡面把 hibernate. show_SQL 設定為 true 就可以。但不建議開啟,開啟之後會降低程式的執行效率。

4.Hibernate 有幾種查詢方式?

    三種:hql、原生 SQL、條件查詢 Criteria。

5.Hibernate 實體類可以被定義為 final 嗎?

    實體類可以定義為 final 類,但這樣的話就不能使用 hibernate 代理模式下的延遲關聯提供效能了,所以不建議定義實體類為 final。

6.在 Hibernate 中使用 Integer 和 int 做對映有什麼區別?

    Integer 型別為物件,它的值允許為 null,而 int 屬於基礎資料型別,值不能為 null。

7.Hibernate 是如何工作的?
  • 讀取並解析配置檔案。
  • 讀取並解析對映檔案,建立 SessionFactory。
  • 開啟 Session。
  • 建立事務。
  • 進行持久化操作。
  • 提交事務。
  • 關閉 Session。
  • 關閉 SessionFactory。
8.get() 和 load() 的區別?
  • 資料查詢時,沒有 OID 指定的物件,get() 返回 null;load() 返回一個代理物件。
  • load()支援延遲載入;get() 不支援延遲載入。
9.說一下 Hibernate 的快取機制?

    Hibernate 常用的快取有一級快取和二級快取:

  • 一級快取:也叫 Session 快取,只在 Session 作用範圍內有效,不需要使用者干涉,由 hibernate 自身維護,可以通過:evict(object)清除 object 的快取;clear()清除一級快取中的所有快取;flush()刷出快取;

  • 二級快取:應用級別的快取,在所有 Session 中都有效,支援配置第三方的快取,如:EhCache。

10.Hibernate 物件有哪些狀態?
  • 臨時/瞬時狀態:直接 new 出來的物件,該物件還沒被持久化(沒儲存在資料庫中),不受 Session 管理。
  • 持久化狀態:當呼叫 Session 的 save/saveOrupdate/get/load/list 等方法的時候,物件就是持久化狀態。
  • 遊離狀態:Session 關閉之後物件就是遊離狀態。
11.在 Hibernate 中 getCurrentSession 和 openSession 的區別是什麼?
  • getCurrentSession 會綁定當前執行緒,而 openSession 則不會。
  • getCurrentSession 事務是 Spring 控制的,並且不需要手動關閉,而 openSession 需要我們自己手動開啟和提交事務。
12.Hibernate 實體類必須要有無參建構函式嗎?為什麼?

    Hibernate 中每個實體類必須提供一個無參建構函式,因為 hibernate 框架要使用 reflection api,通過呼叫 ClassnewInstance() 來建立實體類的例項,如果沒有無參的建構函式就會丟擲異常。

13.MyBatis 中 #{}和 ${}的區別是什麼?

    #{}是預編譯處理,${}是字元替換。 在使用 #{}時,MyBatis 會將 SQL 中的 #{}替換成“?”,配合 PreparedStatement 的 set 方法賦值,這樣可以有效的防止 SQL 注入,保證程式的執行安全。

14.MyBatis 有幾種分頁方式?

    分頁方式:邏輯分頁和物理分頁。

  • 邏輯分頁: 使用 MyBatis 自帶的 RowBounds 進行分頁,它是一次性查詢很多資料,然後在資料中再進行檢索。
  • 物理分頁: 自己手寫 SQL 分頁或使用分頁外掛 PageHelper,去資料庫查詢指定條數的分頁資料的形式。
15.RowBounds 是一次性查詢全部結果嗎?為什麼?

    RowBounds 表面是在“所有”資料中檢索資料,其實並非是一次性查詢出所有資料,因為 MyBatis 是對 jdbc 的封裝,在 jdbc 驅動中有一個 Fetch Size 的配置,它規定了每次最多從資料庫查詢多少條資料,假如你要查詢更多資料,它會在你執行 next()的時候,去查詢更多的資料。就好比你去自動取款機取 10000 元,但取款機每次最多能取 2500 元,所以你要取 4 次才能把錢取完。只是對於 jdbc 來說,當你呼叫 next()的時候會自動幫你完成查詢工作。這樣做的好處可以有效的防止記憶體溢位。

16.MyBatis 邏輯分頁和物理分頁的區別是什麼?
  • 邏輯分頁是一次性查詢很多資料,然後再在結果中檢索分頁的資料。這樣做弊端是需要消耗大量的記憶體、有記憶體溢位的風險、對資料庫壓力較大。
  • 物理分頁是從資料庫查詢指定條數的資料,彌補了一次性全部查出的所有資料的種種缺點,比如需要大量的記憶體,對資料庫查詢壓力較大等問題。
17.MyBatis 是否支援延遲載入?延遲載入的原理是什麼?

    MyBatis 支援延遲載入,設定 lazyLoadingEnabled=true 即可。

    延遲載入的原理的是呼叫的時候觸發載入,而不是在初始化的時候就載入資訊。比如呼叫 a. getB(). getName(),這個時候發現 a. getB() 的值為 null,此時會單獨觸發事先儲存好的關聯 B 物件的 SQL,先查詢出來 B,然後再呼叫 a. setB(b),而這時候再呼叫 a. getB(). getName() 就有值了,這就是延遲載入的基本原理。

18.說一下 MyBatis 的一級快取和二級快取?
  • 一級快取:基於 PerpetualCache 的 HashMap 本地快取,它的生命週期是和 SQLSession 一致的,有多個 SQLSession 或者分散式的環境中資料庫操作,可能會出現髒資料。當 Session flush 或 close 之後,該 Session 中的所有 Cache 就將清空,預設一級快取是開啟的。
  • 二級快取:也是基於 PerpetualCache 的 HashMap 本地快取,不同在於其儲存作用域為 Mapper 級別的,如果多個SQLSession之間需要共享快取,則需要使用到二級快取,並且二級快取可自定義儲存源,如 Ehcache。預設不開啟二級快取,要開啟二級快取,使用二級快取屬性類需要實現 Serializable 序列化介面(可用來儲存物件的狀態)。

    開啟二級快取資料查詢流程:二級快取 -> 一級快取 -> 資料庫。

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

19.MyBatis 和 hibernate 的區別有哪些?
  • 靈活性:MyBatis 更加靈活,自己可以寫 SQL 語句,使用起來比較方便。
  • 可移植性:MyBatis 有很多自己寫的 SQL,因為每個資料庫的 SQL 可以不相同,所以可移植性比較差。
  • 學習和使用門檻:MyBatis 入門比較簡單,使用門檻也更低。
  • 二級快取:hibernate 擁有更好的二級快取,它的二級快取可以自行更換為第三方的二級快取。
20.MyBatis 有哪些執行器(Executor)?

    MyBatis 有三種基本的Executor執行器:

  • SimpleExecutor:每執行一次 update 或 select 就開啟一個 Statement 物件,用完立刻關閉 Statement 物件;
  • ReuseExecutor:執行 update 或 select,以 SQL 作為 key 查詢 Statement 物件,存在就使用,不存在就建立,用完後不關閉 Statement 物件,而是放置於 Map 內供下一次使用。簡言之,就是重複使用 Statement 物件;
  • BatchExecutor:執行 update(沒有 select,jdbc 批處理不支援 select),將所有 SQL 都新增到批處理中(addBatch()),等待統一執行(executeBatch()),它快取了多個 Statement 物件,每個 Statement 物件都是 addBatch()完畢後,等待逐一執行 executeBatch()批處理,與 jdbc 批處理相同。
21.MyBatis 分頁外掛的實現原理是什麼?

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

22.MyBatis 如何編寫一個自定義外掛?
  1. 自定義外掛實現原理
    MyBatis 自定義外掛針對 MyBatis 四大物件(Executor、StatementHandler、ParameterHandler、ResultSetHandler)進行攔截:

    • Executor:攔截內部執行器,它負責呼叫 StatementHandler 操作資料庫,並把結果集通過 ResultSetHandler 進行自動對映,另外它還處理了二級快取的操作;
    • StatementHandler:攔截 SQL 語法構建的處理,它是 MyBatis 直接和資料庫執行 SQL 指令碼的物件,另外它也實現了 MyBatis 的一級快取;
    • ParameterHandler:攔截引數的處理;
    • ResultSetHandler:攔截結果集的處理。
  2. 自定義外掛實現關鍵
    MyBatis 外掛要實現 Interceptor 介面,介面包含的方法,如下:

    public interface Interceptor {   
        Object intercept(Invocation invocation) throws Throwable;       
        Object plugin(Object target);    
        void setProperties(Properties properties);
    }
    
    • setProperties 方法是在 MyBatis 進行配置外掛的時候可以配置自定義相關屬性,即:介面實現物件的引數配置;
    • plugin 方法是外掛用於封裝目標物件的,通過該方法我們可以返回目標物件本身,也可以返回一個它的代理,可以決定是否要進行攔截進而決定要返回一個什麼樣的目標物件,官方提供了示例:return Plugin. wrap(target, this);
    • intercept 方法就是要進行攔截的時候要執行的方法。
  3. 自定義外掛實現示例
    官方外掛實現:

    @Intercepts({@Signature(type = Executor. class, method = "query",args = {MappedStatement. class, Object. class, RowBounds. class,ResultHandler.class})})
    public class TestInterceptor implements Interceptor {
        public Object intercept(Invocation invocation) throws Throwable {
            Object target = invocation. getTarget(); //被代理物件
            Method method = invocation. getMethod(); //代理方法
            Object[] args = invocation. getArgs(); //方法引數
            // do something . . . . . .  方法攔截前執行程式碼塊
        	   Object result = invocation. proceed();
        		// do something . . . . . . . 方法攔截後執行程式碼塊
        		return result;
        }
        public Object plugin(Object target) {
        		return Plugin. wrap(target, this);
        }
    }
    
23.MyBatis 使用了哪些設計模式?
  1. 建造者模式:SqlSessionFactoryBuilder、XMLConfigBuilder、XMLMapperBuilder、XMLStatementBuilder、CacheBuilder;
  2. 工廠模式:SqlSessionFactory、ObjectFactory、MapperProxyFactory;
  3. 單例模式:ErrorContext 和 LogFactory;
  4. 代理模式:Mybatis實現的核心,比如 MapperProxy、ConnectionLogger,用的 jdk 的動態代理;還有 executor.loader 包使用了 cglib 或者 javassist 達到延遲載入的效果;
  5. 組合模式:例如 SqlNode 和 各個子類 ChooseSqlNode 等;
  6. 模板方法模式:例如 BaseExecutor 和 SimpleExecutor,還有 BaseTypeHandler 和所有的子類例如 IntegerTypeHandler;
  7. 介面卡模式:例如 Log 的 Mybatis 介面和它對 jdbc、log4j 等各種日誌框架的適配實現;
  8. 裝飾者模式:Cache 的實現類 LruCache、FifoCache 等都是裝飾一個類PerpetualCache;
  9. 迭代器模式:PropertyTokenizer;
24.MyBatis 除了 select、insert、update、delete外還有哪些常用標籤?
  • sqlMap:Mybatis 配置檔案的頂級標籤;
  • resultMap:定義資料庫表與實體類的對映關係;
  • result:resultMap 的子標籤;
  • sql:定義程式碼片段;
  • include:引入 sql 標籤定義的程式碼片段;
  • if:條件判斷
  • foreach:foreach標籤主要用於構建in條件,可在sql中對集合進行迭代;
  • choose:按順序判斷when中的條件出否成立;
  • where:動態配置 where 關鍵字;
  • set:動態配置 set 關鍵字;
  • trim:格式化輸出,也可以通過trim標籤設定或忽略前後綴來實現;
  • collection、association:配置多張表的關聯關係;