動態

詳情 返回 返回

面試必問:MyBatis 高頻面試題! - 動態 詳情

這些都是面試常見的問題,看看下面的問題你都能答得上來嗎?

1.什麼是 MyBatis?它有哪些主要特性和優勢?
2. mybatis 和數據庫交互的原理?
3. mybatis 中#{}、${}的區別
4. Mybatis 自帶連接池都有什麼?
5. Mybatis 的一級、二級緩存?
6. MyBatis 是如何進行分頁的?分頁插件的原理是什麼?
7. mybatis 中常見的設計模式有哪些?

1. 什麼是 MyBatis?它有哪些主要特性和優勢?

MyBatis 是一個優秀的持久層框架,它支持自定義 SQL、存儲過程以及高級映射。MyBatis 消除了幾乎所有的 JDBC 代碼和手動設置參數以及獲取結果集的工作。MyBatis 可以使用簡單的 XML 或註解來配置和映射原生類型、接口和 Java POJO 到數據庫中的記錄。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.basic.mapper.EmployeesDao">

    <resultMap type="org.example.basic.entity.Employees" id="EmployeesMap">
        <result property="employeeId" column="employee_id" jdbcType="INTEGER"/>
        <result property="name" column="name" jdbcType="VARCHAR"/>
        <result property="password" column="password" jdbcType="VARCHAR"/>
    </resultMap>

    <select id="list" resultMap="EmployeesMap">
        select
        employee_id,name,password
        from employees
        <where>
            <if test="employeeId != null">
                and employee_id = #{employeeId}
            </if>
            <if test="name != null and name != ''">
                and name like concat('%',#{name},'%')
            </if>
            <if test="password !=null and password !=''">
                and password = #{password}
            </if>
        </where>
    </select>

</mapper>

2. mybatis 和數據庫交互的原理?

mybatis 和數據庫交互主要分為幾個階段,
第一步是 mybatis 會去加載配置文件,獲取必要的基礎的信息。
然後創建出 sqlsessionfactory 工廠,工廠會幫助我們進行環境初始化,數據源加載等等。
然後創建一個 sqlsession 對象,sqlsession 承擔了與數據庫交互的核心。
每次執行數據庫操作,可以從 sqlsession 裏面獲取到需要執行的 mapper。
然後通過 mapper 開始執行 sql,獲取數據。
如果涉及事務也是 session 幫助我們來做事務提交或回滾的操作。

詳細流程

初始化階段
  1. 加載全局配置文件 (mybatis-config.xml)
  • 使用 Resources.getResourceAsStream 方法讀取 MyBatis 全局配置文件。
  • 解析配置文件中的<environments>、<mappers>等節點,加載數據源、事務管理器和 Mapper 文件。
  1. 創建 SqlSessionFactory
  • 使用 SqlSessionFactoryBuilder 構建 SqlSessionFactory 對象。
  • SqlSessionFactory 會根據配置文件初始化 MyBatis 環境,包括數據源、事務管理器和 Mapper 文件。
獲取 SqlSession
  1. 打開 SqlSession
  • 從 SqlSessionFactory 獲取一個新的 SqlSession 實例。SqlSession 是 MyBatis 與數據庫交互的核心對象,負責執行 SQL 語句、獲取 Mapper 接口實例、管理事務等。
Mapper 接口操作
  1. 獲取 Mapper 接口實例
  • 通過 SqlSession 獲取 Mapper 接口的實現類實例。MyBatis 會在運行時生成 Mapper 接口的實現類,並通過 SqlSession 獲取其實例。
執行 SQL 語句
  1. 調用 Mapper 方法
  • 調用 Mapper 接口的方法,例如 mapper.selectUserById(1);
  1. 參數處理
  • 將方法參數轉換為 SQL 語句中的佔位符(如#{id})所需的值。MyBatis 使用 TypeHandler 將 Java 類型轉換為 JDBC 類型。
  1. 執行 SQL 語句
  • MyBatis 使用 JDBC 通過數據源執行 SQL 語句,數據庫返回結果集。
  1. 結果映射
  • 將 SQL 查詢結果集映射為 Java 對象。根據映射文件或註解中的配置,將結果集中的數據映射到 Java 對象的屬性中。
事務管理
  1. 提交事務
  • 如果執行的數據操作需要提交事務,調用 session.commit();提交事務,提交事務會將所有未提交的更改保存到數據庫。
  1. 回滾事務
  • 如果操作過程中發生異常,需要回滾事務,調用 session.rollback();回滾事務,回滾事務會撤銷所有未提交的更改。
關閉資源
  1. 關閉 SqlSession
  • 操作完成後,調用 session.close();關閉 SqlSession,釋放數據庫連接。
// 1. 加載配置文件並創建 SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. 獲取 SqlSession
try (SqlSession session = sqlSessionFactory.openSession()) {
    // 3. 獲取 Mapper 接口實例
    UserMapper mapper = session.getMapper(UserMapper.class);
    // 4. 執行 SQL 語句
    User user = mapper.selectUserById(1);
    System.out.println(user);
    // 5. 提交事務(如果有數據修改操作)
    session.commit();
} catch (Exception e) {
    // 5. 回滾事務
    session.rollback();
    e.printStackTrace();
} finally {
    // 6. 關閉 SqlSession
    session.close();
}

3. mybatis 中#{}、${}的區別

  1. #{}(預編譯方式)
  • 安全性:#{} 採用了預編譯(PreparedStatement)的方式,有效防止了 SQL 注入。因為 MyBatis 會將 #{} 中的內容當作參數處理,而不是直接拼接到 SQL 語句中。
  • 處理方式:MyBatis 會為 #{}中的內容生成一個參數佔位符 ?,並使用 PreparedStatement 的 setXXX() 方法來設置參數值。因此,你不需要擔心數據類型或引號問題。
  • 例子:

    • SELECT * FROM users WHERE id = #{userId},這條 SQL 語句在 MyBatis 中處理時,會將其轉換為類似 SELECT * FROM users WHERE id = ?的形式,並通過 PreparedStatement 的 setInt() 或其他相關方法來設置 userId 的值。
  1. ${}(字符串拼接方式)
  • 安全性:${}是直接字符串拼接的方式,所以存在 SQL 注入的風險。如果參數來自用户輸入或其他不可信的來源,那麼使用 ${} 是非常危險的。
  • 處理方式:MyBatis 會直接將${} 中的內容替換到 SQL 語句中。這意味着你需要自己處理數據類型、引號等問題。
  • 用途:雖然 ${}存在安全風險,但在某些場景下它是必要的。例如,當你要動態地構建表名或列名時,就必須使用${}
  • 例子:SELECT * FROM ${tableName},這裏的 tableName 是一個變量,MyBatis 會直接將其替換到 SQL 語句中。因此,如果你不能保證 tableName 的來源是可信的,那麼這條 SQL 語句就存在 SQL 注入的風險。

4. Mybatis 自帶連接池都有什麼?

MyBatis 自帶的連接池實現主要有兩種:PooledDataSourceUnpooledDataSource。這兩種連接池實現提供了不同的特性和使用場景。

UnpooledDataSource

UnpooledDataSource 是 MyBatis 提供的一個簡單的、未池化的連接池實現。每次請求數據庫連接時,UnpooledDataSource 都會創建一個新的連接,而不是從連接池中獲取連接。這種實現適用於對性能要求不高的小型應用或測試環境。

<environment id="development">
    <transactionManager type="JDBC"/>
    <dataSource type="UNPOOLED">
        <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mydatabase"/>
        <property name="username" value="root"/>
        <property name="password" value="password"/>
    </dataSource>
</environment>

PooledDataSource

PooledDataSource 是 MyBatis 提供的一個簡單的連接池實現。它維護了一組數據庫連接,以便在需要時快速提供連接,而不需要每次都創建新的連接。PooledDataSource 提供了基本的連接池功能,如連接池大小、連接超時等。

<environment id="development">
    <transactionManager type="JDBC"/>
    <dataSource type="POOLED">
        <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mydatabase"/>
        <property name="username" value="root"/>
        <property name="password" value="password"/>
        <property name="poolMaximumActiveConnections" value="10"/>
        <property name="poolMaximumIdleConnections" value="5"/>
        <property name="poolMaximumCheckoutTime" value="20000"/>
        <property name="poolTimeToWait" value="20000"/>
    </dataSource>
</environment>

選擇連接池實現

  • 雖然 MyBatis 提供了內置的連接池實現,但在生產環境中,通常推薦使用功能更強大、性能更好的第三方連接池,例如:

    • HikariCP:以高性能和低延遲著稱。
    • Druid:一個成熟且廣泛使用的連接池實現。
    • C3P0:一個功能豐富的連接池實現,適用於需要高級功能的場景。
  • 使用第三方連接池時,可以通過配置 MyBatis 使用外部的數據源來替代內置的連接池。

5. Mybatis 的一級、二級緩存?

1. 一級緩存

  • MyBatis 的一級緩存 是用來減少數據庫查詢次數的,每個 SqlSession 都有自己的緩存。這個緩存默認是開啓的,不需要額外配置。
  • 緩存只在同一個 SqlSession 內有效,不同的 SqlSession 之間互不影響。執行增刪改操作、調用 commit() 或 rollback() 方法,或者關閉 SqlSession 時,緩存會被清空。
  • 當你執行查詢操作時,MyBatis 會先看看緩存裏有沒有數據。如果有,就直接用緩存裏的數據,不用再去查數據庫。如果沒有,就去查數據庫,然後把結果放進緩存裏。
  • MyBatis 用查詢的 SQL 語句和參數作為緩存的鍵。

2. 二級緩存

  • mybatis 的二級緩存 ,相比與一級,其實更加的牛,相當於是跨 session 級別的緩存機制。
  • 不同的 sqlsession 可以共享緩存,而在一級中,是彼此獨立的。
  • 二級緩存默認是關閉的,需要我們進行一波手動的開啓。
  • 二級緩存會將查詢結果存儲在內存中,以鍵值對的形式保存。Key 通常是查詢語句及其參數的組合,Value 是查詢結果。
  • 當執行更新、插入或刪除操作時,相關的緩存條目會被自動清除。可以集成第三方緩存框架,通過配置<cache>標籤中的 type 屬性來指定緩存提供者。

6. MyBatis 是如何進行分頁的?分頁插件的原理是什麼?

  • Mybatis 使用 RowBounds 對象進行分頁,它是針對 ResultSet 結果集執行的內存分頁,而非物理分頁,可以在 sql 內直接書寫帶有物理分頁的參數來完成物理分頁功能,也可以使用分頁插件來完成物理分頁。
  • 分頁插件的基本原理是使用 Mybatis 提供的插件接口,實現自定義插件,在插件的攔截方法內攔截待執行的 sql,然後重寫 sql,根據 dialect 方言,添加對應的物理分頁語句和物理分頁參數。
  • 例子:select * from student,攔截 sql 後重寫為:select t.* from (select * from student) t limit 0, 10

7. mybatis 中常見的設計模式有哪些?

mybatis 中應用了大量的設計模式,常見的有工廠模式,單例模式,代理模式等,下面是詳細的常見設計模式。
1. 工廠模式
  • 在創建複雜對象時使用。MyBatis 使用 SqlSessionFactory 來創建 SqlSession 實例。SqlSessionFactory 本身是由 SqlSessionFactoryBuilder 創建的。
2. 單例模式
  • MyBatis 的 Configuration 類使用了單例模式,確保在一個 SqlSessionFactory 中只有一個 Configuration 實例。
3. 代理模式
  • 為其他對象提供一種代理以控制對這個對象的訪問。MyBatis 使用動態代理為 Mapper 接口生成實現類,從而在調用 Mapper 方法時執行 SQL 語句。
4. 模板方法模式
  • 定義一個操作中的算法的骨架,而將一些步驟延遲到子類中。MyBatis 的 Executor 接口及其實現類使用了模板方法模式,定義了執行 SQL 語句的基本流程,而具體的執行細節由子類實現。
5. 建造者模式
  • SqlSessionFactoryBuilder:MyBatis 使用 SqlSessionFactoryBuilder 來構建 SqlSessionFactory 實例。
6. 裝飾器模式(Decorator Pattern)
  • 插件機制:MyBatis 的插件機制使用了裝飾器模式,可以在執行器、參數處理器等核心組件上添加額外的功能。
7. 策略模式(Strategy Pattern)
  • 緩存策略:MyBatis 的緩存機制使用了策略模式,不同的緩存實現可以互相替換。
8. 責任鏈模式(Chain of Responsibility Pattern)
  • 攔截器鏈:MyBatis 的攔截器機制使用了責任鏈模式,可以在執行 SQL 語句的過程中通過一系列攔截器進行處理。

就業陪跑訓練營學員投稿

歡迎關注 ❤

我們搞了一個免費的面試真題共享羣,互通有無,一起刷題進步。

沒準能讓你能刷到自己意向公司的最新面試題呢。

感興趣的朋友們可以加我微信:wangzhongyang1993,備註:思否面試羣。

user avatar u_17513518 頭像 manongsir 頭像 sofastack 頭像 AmbitionGarden 頭像 u_11365552 頭像 candy_68fb0dfb0afd0 頭像 puxiaoke6 頭像 pannideniupai 頭像 digitalocean 頭像 devlive 頭像 pottercoding 頭像 buyaomingdeshuilongtou_orcjl 頭像
點贊 19 用戶, 點贊了這篇動態!
點贊

Add a new 評論

Some HTML is okay.