中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Mybatis最硬核的API是什么

發布時間:2021-10-20 15:40:30 來源:億速云 閱讀:163 作者:iii 欄目:編程語言

本篇內容主要講解“Mybatis最硬核的API是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Mybatis最硬核的API是什么”吧!

1、Mybatis 架構與核心API

不出意外的話,在后續源碼剖析相關文章中,我們會對 Mybatis 的源碼進行一次大掃蕩,一起挖掘每一處值得大家深入理解/記憶的知識點。而在本文中,我們主要先把 Mybatis 的架構/層次鋪開,俯視 Mybatis 架構的設計全貌,再把幾個硬核的 API 詳細消化。

整體順序脈絡,希望讓你有所期待 ~

Mybatis最硬核的API是什么

我們先簡單揭開 Mybatis 神秘的源碼包,

瞅瞅 Ta 大致目錄結構 :

Mybatis最硬核的API是什么

看,Mybatis 的源代碼包整齊劃一排在 org.apache.ibatis 目錄下,基本設計用途我簡單梳理成上面這張圖,方便大家直觀理解,當然只看源碼包目錄結構,難免會顯得枯燥無物,所以我們再看一下,其實 Mybatis 的源碼包功能上可以是這么劃分:

Mybatis最硬核的API是什么

上圖讓我們對 Mybatis 的架構有了抽象的理解。

然而,實際上具體的職能分工,核心 API 的場景應用,到底會是怎樣一套流程呈現呢?

看下面這幅功能架構設計,或許你能更好的理解。

Mybatis最硬核的API是什么

根據 Mybatis 功能架構我們劃分成三層

  • 接口層:該層提供一系列接口讓用戶直接參與使用,包含信息配置與實際數據操作調用。配置方式包括:基于 XML 配置方式、基于 Java API 配置方式兩種方式,用戶也可以通過接口層 API 對數據庫發起增刪改查等操作的請求, 本層接口會把接收到的調用請求交給數據處理層的構件去處理。

  • 數據處理層:該層是 Mybatis 的核心層,負責數據處理,主要包括SQL 參數映射解析、SQL 語句的實際執行、執行結果集的映射處理等。

  • 框架支撐層:該層屬于 Mybatis 的后勤保障層,包括數據庫連接管理、事務把控管理、配置加載與緩存處理、日志處理、異常處理等,提供基礎支撐能力,保障上層的數據處理。

我們知道,Mybatis 框架讓用戶只需要提供配置信息,并且專注于 SQL 的編寫即可,對于連接管理數據庫/事務,或實際的 SQL 參數映射/語句執行/結果集映射等操作,作為用戶都并不需要操心和參與。

但是,好奇的我們其實想知道,Mybatis 核心部分的數據處理在整體流程中,是如何支撐用戶請求?同時各個構件之間交互,又是怎樣流轉呢?

很巧,我這里有一張圖,介紹了整體流程:

Mybatis最硬核的API是什么

根據以上框架流程圖進行講解

  • 創建配置并調用API:這一環節發生在應用程序端,是開發人員在實際應用程序中進行的兩步操作,第一步創建核心配置文件 Configuration.xml 和映射文件 mapper.xml (通過注解方式也可創建以上兩種配置),準備好基礎配置和 SQL 語句之后;第二步就是直接調用 Mybatis 框架中的數據庫操作接口。

  • 加載配置并初始化:Mybatis 框架會根據應用程序端提供的核心配置文件與 SQL 映射文件的內容,使用資源輔助類 Resources 把配置文件讀取成輸入流,然后通過對應的解析器解析并封裝到 Configuration 對象和 MappedStatement 對象,最終把對象存儲在內存之中。

  • 創建會話并接收請求:在 Mybatis 框架加載配置并初始化配置對象之后,會話工廠構建器 SqlSessionFactoryBuilder 同時創建會話工廠 SqlSessionFactory,會話工廠會根據應用程序端的請求,創建會話 SqlSession,以便應用程序端進行數據庫交互。

  • 處理請求:SqlSession 接收到請求之后,實際上并沒有進行處理,而是把請求轉發給執行器 Executor,執行器再分派到語句處理器 StatementHandler ,語句處理器會結合參數處理器 ParameterHandler ,進行數據庫操作(底層封裝了 JDBC Statement 操作)。

  • 返回處理結果:每個語句處理器 StatementHandler 處理完成數據庫操作之后,會協同 ResultSetHandler 以及類型處理器 TypeHandler ,對底層 JDBC 返回的結果集進行映射封裝,最終返回封裝對象。

針對以上總體框架流程涉及到的這些硬核 API,下面我們逐個展開介紹,但不會詳細剖析源碼與原理,包括構建細節,因為這些我們在后續的源碼剖析章節中都會詳細分析。

Mybatis最硬核的API是什么

2、Configuration – 全局配置對象

對于 Mybatis 的全局配置對象 Configuration,我相信無論是初學者還是資深玩家,都不會陌生。整個 Mybatis 的宇宙,都圍繞著 Configuration 轉。Configuration 對象的結構和 config.xml 配置文件的內容幾乎相同,涵蓋了properties (屬性),settings (設置),typeAliases (類型別名),typeHandlers (類型處理器),objectFactory (對象工廠),mappers (映射器)等等,之前我們有專門的一篇文章詳細進行介紹,感興趣的朋友往上翻到目錄列表,找到 《Mybatis系列全解(四):全網最全!Mybatis配置文件XML全貌詳解》 一文詳細品味一番吧。

Mybatis最硬核的API是什么

配置對象 Configuration 通過解析器 XMLConfigBuilder 進行解析,把全局配置文件 Config.xml 與 映射器配置文件 Mapper.xml 中的配置信息全部構建成完整的 Configuration 對象,后續我們源碼分析時詳細剖析整個過程。

Mybatis最硬核的API是什么

3、Resources – 資源輔助類

我們知道,像 Configuration 和 Mapper 的配置信息存放在 XML 文件中,Mybatis 框架在構建配置對象時,必須先把 XML 文件信息加載成流,再做后續的解析封裝,而 Resources 作為資源的輔助類,恰恰干的就是這個活,無論是通過加載本地資源或是加載遠程資源,最終都會通過 類加載器 訪問資源文件并輸出文件流。

Mybatis最硬核的API是什么

//加載核心配置文件
InputStream resourceAsStream = 
    Resources.getResourceAsStream("Config.xml");

Resources 實實在在提供了一系列方法分分鐘解決你的文件讀取加載問題:

Mybatis最硬核的API是什么

Mybatis最硬核的API是什么

4、SqlSessionFactoryBuilder – 會話工廠構建器

我們一撞見 xxxBuilder ,就大致能知道它是某類對象的構建器,這里 SqlSessionFactoryBuilder 也是一樣,它是 Mybatis 中的一個會話工廠構建器,在資源輔助類 Resources 讀取到文件流信息之后,它負責解析文件流信息并構建會話工廠 SqlSessionFactory。(解析的配置文件包含:全局配置 Configuration 與映射器 Mapper)

Mybatis最硬核的API是什么

在程序應用端,我們一般使用 SqlSessionFactoryBuilder 直接構建會話工廠:

// 獲得sqlSession工廠對象
SqlSessionFactory sqlSessionFactory = 
    new SqlSessionFactoryBuilder().build(resourceAsStream);

當然,如果你集成了 Spring 框架的項目,則不需要自己手工去構建會話工廠,直接在 Spring 配置文件中指定即可,例如指定一個 bean 對象,id 是 sqlSessionFactory,而 class 類指定為 org.mybatis.spring.SqlSessionFactoryBean 。

SqlSessionFactoryBuilder 內部通過解析器 XMLConfigBuilder 解析了文件流,同時封裝成為配置對象 Configuration ,再把 Configuration 對象進行傳遞并構建實例。

public SqlSessionFactory build(
    InputStream inputStream, 
    String environment, 
    Properties properties) {
   
     
      // 配置解析器解析
      XMLConfigBuilder parser = 
          new XMLConfigBuilder(
          	inputStream,environment, properties);
    
      // 最終實例會話工廠
      return build(parser.parse()); 
    
}

最終實例會話工廠,其實 Mybatis 默認實現是 new 了一個DefaultSqlSessionFactory 實例。

// 最終實例會話工廠
public SqlSessionFactory build(Configuration config) {
   
    return new DefaultSqlSessionFactory(config);
}

會話工廠構建器 SqlSessionFactoryBuilder 應用了構建者模式,主要目的就是為了構建 SqlSessionFactory 對象,以便后續生產 SqlSession 對象,這個構造器基本上算是 Mybatis 框架的入口構建器,它提供了一系列多態方法 build(),支持用戶使用 XML 配置文件或 Java API (Properties)來構建會話工廠 SqlSessionFactory 實例。

SqlSessionFactoryBuilder 的一生只為成就 SqlSessionFactory,當 SqlSessionFactory 一經實例,SqlSessionFactoryBuilder 使命完成,便可消亡,便可被丟棄。

Mybatis最硬核的API是什么

因此 SqlSessionFactoryBuilder 實例的最佳作用域是 方法作用域(也就是局部方法變量)。 你可以重用 SqlSessionFactoryBuilder 來創建多個 SqlSessionFactory 實例,但最好不要一直保留著它,以保證所有的 XML 解析資源可以被釋放給更重要的事情。

SqlSessionFactoryBuilder 中靈活構建會話工廠的一系列接口:

Mybatis最硬核的API是什么

Mybatis最硬核的API是什么

5、SqlSessionFactory – 會話工廠

會話工廠 SqlSessionFactory 是一個接口,作用是生產數據庫會話對象 SqlSession ,有兩個實現類:

  • **DefaultSqlSessionFactory **(默認實現)

  • **SqlSessionManager **(僅多實現了一個 Sqlsession 接口,已棄用)

在介紹會話工廠構建器 SqlSessionFactoryBuilder 的時候,我們了解到構建器默認創建了 DefaultSqlSessionFactory 實例,并且會話工廠本身會綁定一個重要的屬性 Configuration 對象,在生產會話時,最終也會把 Configuration 配置對象傳遞并設置到會話 SqlSession 上。

Mybatis最硬核的API是什么

會話工廠可以簡單創建 SqlSession 實例:

// 創建 SqlSession 實例
SqlSession session = sqlSessionFactory.openSession();

會話工廠創建 SqlSession 時,會綁定數據源、事務處理、執行器等等,默認會話工廠實現類 DefaultSqlSessionFactory 在創建會話對象時,最終都會調用 openSessionFromDataSource 方法 ,即是如此實現:

// 每一個 openSession 最終都會調用此處
private SqlSession openSessionFromDataSource(
    ExecutorType execType, 
    TransactionIsolationLevel level, 
    boolean autoCommit) {
   
    
    // 環境配置
    final Environment environment = 
        configuration.getEnvironment();
    
    // 事務工廠
    final TransactionFactory transactionFactory = 
        getTransactionFactoryFromEnvironment(environment);
    
    // 事務
    Transaction tx =
        transactionFactory.newTransaction(
        environment.getDataSource(), 
        level, 
        autoCommit);
    
    // 執行器
    final Executor executor = 
        configuration.newExecutor(tx, execType);
    
    // 最終生成會話
    return new DefaultSqlSession(
          configuration, executor, autoCommit);
    
  }

另外,會話工廠其實提供了一系列接口來靈活生產會話 SqlSession,你可以指定:

  • 事務處理:你希望在 session 作用域中使用/開啟事務作用域(也就是不自動提交事務),還是使用自動提交(auto-commit),sqlSession 默認不提交事務,對于增刪改操作時需要手動提交事務。

  • 數據庫連接:你希望 MyBatis 幫你從已配置的數據源獲取連接,還是使用自己提供的連接,可以動態創建數據源對象 Connection。

  • 執行器類型:你希望指定某類執行器來創建/執行/預處理語句,可以有普通執行器(SimpleExecutor),或復用執行器(ReuserExecutor)、還是批量執行器(BatchExecutor)等,下面介紹執行器時會詳細說明。

  • 事務隔離級別支持:支持 JDBC 的五個隔離級別(NONE、READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ 和 SERIALIZABLE),對于事務相關的內容,我們后續 《spring 系列全解》 會詳細講,這里簡單說明一下就是事務隔離級別主要為了解決例如臟讀、不可重復讀、幻讀等問題,使用不同的事務隔離級別勢必會導致不同的數據庫執行效率,因此我們再不同的系統/功能中,對隔離級別有不同的需求。

Mybatis最硬核的API是什么

SqlSessionFactory 一旦被創建就應該在 應用的運行期間 一直存在,沒有任何理由丟棄它或重新創建另一個實例。 使用 SqlSessionFactory 的最佳實踐是在應用運行期間不要重復創建多次,多次重建 SqlSessionFactory 被視為一種代碼“壞習慣”。因此 SqlSessionFactory 的最佳作用域是 應用作用域。 最簡單的就是使用單例模式或者靜態單例模式。

請記住,創建 SqlSessionFactory ,一次就好!

每個數據庫對應一個 SqlSessionFactory 實例。SqlSessionFactory 一旦被創建, 它的生命周期應該與應用的生命周期相同 。所以,如果你想連接兩個數據庫,就需要創建兩個 SqlSessionFactory 實例,每個數據庫對應一個;而如果是三個數據庫,就需要三個實例,依此類推。

Mybatis最硬核的API是什么

Mybatis最硬核的API是什么

6、SqlSession – 會話

SqlSession 是一個接口,有兩個實現類:

  • DefaultSqlSession(默認實現)

  • SqlSessionManager (已棄用)

簡單來說,通過會話工廠構建出 SqlSession 實例之后,我們就可以進行增刪改查了,默認實例 DefaultSqlSession 提供了如此多的方法供用戶使用,有超過30個:

Mybatis最硬核的API是什么

sqlSession 的方法除了 CURD,還提供了事務的控制例如提交/關閉/回滾等、提供了配置對象的獲取例如 getConfiguration()、提供了批量語句的執行更新例如 flushStatements()、提供了緩存清除例如 clearCache() 、提供了映射器的使用 getMapper() 等等。

Mybatis最硬核的API是什么

對于客戶端應用層面來說,熟悉 sqlSession 的 API 基本就可以任意操作數據庫了,不過我們希望想進一步了解 sqlSession 內部是如何執行 sql 呢?其實 sqlSession 是 Mybatis 中用于和數據庫交互的 頂層類,通常將它與本地線程 ThreadLocal 綁定,一個會話使用一個 SqlSession,并且在使用完畢之后進行 關閉

之所以稱 SqlSession 為數據交互的 頂層類,是它其實沒有完成實質的數據庫操作。根據之前的架構設計流程我們已經清晰的知道,SqlSession 對數據庫的操作都會轉發給具體的執行器 Executor 來完成 ;當然執行器也是甩手掌柜,執行器 Executor 會再分派給語句處理器 StatementHandler ,語句處理器會結合參數處理器 ParameterHandler ,共同完成最終的數據庫執行處理操作(底層還是封裝了 JDBC Statement 操作)。并在每個語句處理器 StatementHandler 處理完成數據庫操作之后, 通過結果結處理器 ResultSetHandler 以及類型處理器 TypeHandler ,對底層 JDBC 返回的結果集進行映射封裝,最終才返回預期的封裝對象。

關注以下圖示 sqlSession 紅色高亮位置,詳細描述了會話的實際執行路徑:

Mybatis最硬核的API是什么

SqlSession 可以理解為一次數據庫會話,一次會話當中既可以執行一次 sql ,也允許你批量執行多次,但是一旦會話關閉之后想要再執行 sql,那就必須重新創建會話。

Mybatis最硬核的API是什么

每個線程都應該有它自己的 SqlSession 實例,SqlSession 的實例不是線程安全的,因此是不能被共享的,所以它的最佳的作用域是 請求(request)或方法(method) 作用域。 絕對不能將 SqlSession 實例的引用放在一個類的靜態域,甚至一個類的實例變量也不行。 也絕不能將 SqlSession 實例的引用放在任何類型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你現在正在使用一種 Web 框架,考慮將 SqlSession 放在一個和 HTTP 請求相似的作用域中。 換句話說,每次收到 HTTP 請求,就可以打開一個 SqlSession,返回一個響應后,就關閉它。 這個關閉操作很重要,為了確保每次都能執行關閉操作,你應該把這個關閉操作放到 finally 塊中。

Spring 集成 Mybatis 之后,通過依賴注入可以創建線程安全的、基于事務的 SqlSession ,并管理他們的生命周期,推薦搭配使用。

Mybatis最硬核的API是什么

7、Executor – 執行器

Executor 是一個執行器接口,是 Mybatis 的調度核心,它定義了一組管理 Statement 對象與獲取事務的方法,并負責 SQL 語句的生成和一級/二級查詢緩存的維護等,SqlSessionFactory 在創建 SqlSession 時會同時創建執行器,并指定執行器類型,默認使用 SimpleExecutor 。執行器接口有5個子孫實現類,其中 BaseExecutor 是抽象類,另外4個子孫實現類分別是:SimpleExecutor 、BatchExecutor、ReuseExecutor、CachingExecutor。

Mybatis最硬核的API是什么

  • BaseExecutor:基礎執行器(抽象類),對Executor接口進行了基本實現,為下一級實現類執行器提供基礎支持。BaseExecutor 有三個子類分別是 SimpleExecutor、ResuseExecutor、BatchExecutor。

  • SimpleExecutor:普通執行器,繼承 BaseExecutor 抽象類,是 MyBatis 中 默認 使用的執行器. 每執行一次 update 或 select ,就開啟一個 Statement 對象,用完立刻關閉 Statement 對象。(可以是 Statement 或 PrepareStatement 對象)。

  • ReuseExecutor:復用執行器,繼承 BaseExecutor 抽象類,這里的復用指的是重復使用 Statement . 它會在內部利用一個 Map 把創建的 Statement 都緩存起來,每次在執行一條 SQL語 句時,它都會去判斷之前是否存在基于該 SQL 緩存的 Statement 對象,存在且之前緩存的 Statement 對象對應的 Connection 還沒有關閉則會繼續使用之前的 Statement 對象,否則將創建一個新的 Statement 對象,并將其緩存起來。因為每一個新的 SqlSession 都有一個新的 Executor 對象,所以我們緩存在 ReuseExecutor 上的 Statement 的作用域是同一個 SqlSession 。

  • BatchExecutor:批處理執行器,繼承 BaseExecutor 抽象類,通過批量操作來提高性能,用于將多個 sql 語句一次性輸送到數據庫執行。由于內部有緩存的實現,所以使用完成后需要調用 flushStatements() 來清除緩存。

  • CachingExecutor : 緩存執行器,繼承 BaseExecutor 抽象類,它為 Executor 對象增加了 二級緩存 的相關功能,cachingExecutor 有一個重要屬性 delegate,即為委托的執行器對象,可以是 SimpleExecutor、ReuseExecutor、BatchExecutor 中任意一個。CachingExecutor 在執行數據庫 update 操作時,它直接調用 委托對象 delegate 的 update 方法;而執行查詢時,它會先從緩存中獲取查詢結果,存在就返回,不存在則委托 delegate 去數據庫取,然后存儲到緩存 cache 中。

Mybatis 在構建 Configuration 配置類時默認把 ExecutorType.SIMPLE 作為執行器類型,當我們的會話工廠 DefaultSqlSessionFactory 開始生產 SqlSession 會話時,會同時構建執行器,此時就會依據配置類 Configuration 構建時指定的執行器類型來實例具體執行器 ,流程如下:

// 1、Configuration配置類構建時
// 指定了默認執行器類型為:普通執行器
protected ExecutorType defaultExecutorType 
    = ExecutorType.SIMPLE;

// 2、Configuration配置類中
// 提供方法獲取默認執行器類型
public ExecutorType getDefaultExecutorType() {
   
    return defaultExecutorType;
}

// 3、會話工廠創建 SqlSession 實例時
SqlSession session = sqlSessionFactory.openSession();

// 4、openSession 實際邏輯
public SqlSession openSession() {
   
    return 
       openSessionFromDataSource(
           // 這里可就獲取了默認執行器
           configuration.getDefaultExecutorType(), 
           null, 
           false
        );
}

這里,肯定有人想知道,我們能否指定其它執行器呢?

答案是:當然可以,有兩種方式指定:

  • 第一種方式是通過 Java API 指定,在開啟會話 openSession 時進行指定。例如:

// 創建 SqlSession 實例
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.REUSE)
    
// ExecutorType是一個枚舉
// 有三個值SIMPLE, REUSE, BATCH
  • 另一種通過 Configuration 配置方式來指定默認執行器類型。例如

<settings>
    <!--取值范圍 SIMPLE, REUSE, BATCH -->
	<setting name="defaultExecutorType" value="REUSE"/>
</settings>

對于第二種 settings 的配置方式,其實之前我們在介紹 Mybatis 的配置文件中已經講過,這里再簡單說明一下,像上面配置 settings 中的屬性 defaultExecutorType ,基本這些屬性都是 Mybatis 額外提供給我們靈活設置的,就算我們不設置 Mybatis 也會有默認值,例如像 defaultExecutorType 的默認值就是 SIMPLE。你看一下 Mybatis 在解析 Configuration 配置時的默認構建,就會明白:

解析 Configuration 的解析器(類與具體方法的代碼路徑):

org.apache.ibatis.builder.xml.XMLConfigBuilder#settingsElement

我們截取部分代碼邏輯,下面是設置默認執行器類型屬性 defaultExecutorType 的內容:

// 配置文件解析器 
public class XMLConfigBuilder {
   
    
    // 最終解析到的 Configuration 對象
    protected final Configuration configuration;
    
    // 為 Configuration 對象設置屬性
    private void settingsElement(Properties props) {
   
        
        // 設置默認執行器類型,默認是 SIMPLE
        configuration.setDefaultExecutorType(
            ExecutorType.valueOf(
                props.getProperty(
                    "defaultExecutorType", "SIMPLE")));
        
        // .... 當然這里還有很多屬性設置
        // .... 只要你在<settings>中配置即可
    
    }
}

注意,到此我們知道可以根據業務需要指定執行器類型,例如 SIMPLE(普通執行器), REUSE(復用執行器), BATCH(批處理執行器)。

但是,有朋友就好奇了,那緩存執行器 CachingExecutor 好像不見說明呢?

確實如此,因為緩存執行器個其它三個執行器還不太一樣,CachingExecutor 是需要我們開啟二級緩存才會有,這里大家先不要思考什么是一級緩存,什么二級緩存,后續我們有一文會詳細講緩存整個知識內容。

大家先了解一個概念即可,就是 Mybatis 的一級緩存是默認開啟的,不管你要不要,都會有一級緩存,而二級緩存呢,是默認關閉的,但允許我們手工開啟。

對比開啟二級緩存前后,執行器執行的區別吧!

  • 不開啟二級緩存,執行器執行時

Mybatis最硬核的API是什么

  • 開啟二級緩存之后,執行器執行時

Mybatis最硬核的API是什么

其實我們實際操作數據庫,不會直接接觸到執行器 Executor ,不過我們確實可以了解一下基本的執行原理,下面列出了執行器接口提供的眾多重載方法,基本用于事務/緩存/數據庫管理與訪問,可以知道一下:

Mybatis最硬核的API是什么

到此,對于執行器有了基本的認識,但是實際上,我們知道執行器自身沒有去具體執行 SQL 語句,而是分派到語句處理器 StatementHandler ,語句處理器會結合參數處理器 ParameterHandler ,最終進行數據庫操作。

Mybatis最硬核的API是什么

8、StatementHandler – 語句處理器

StatementHandler 是一個語句處理器接口,它封裝了 JDBC Statement 操作,負責對 JDBC Statement 的操作,如 設置參數、結果集映射,是實際跟數據庫做交互的一道。StatementHandler 語句處理器實例,是在執行器具體執行 CRUD 操作時構建的,默認使用 PrepareStatementHandler。語句處理器接口有5個子孫實現類,其中 BaseStatementHandler 是抽象類,另外4個子孫實現類分別是:SimpleStatementHandler、PrepareStatementHandler、CallableStatementHandler、RoutingStatementHandler。

Mybatis最硬核的API是什么

  • BaseStatementHandler:基礎語句處理器(抽象類),它基本把語句處理器接口的核心部分都實現了,包括配置綁定、執行器綁定、映射器綁定、參數處理器構建、結果集處理器構建、語句超時設置、語句關閉等,并另外定義了新的方法 instantiateStatement 供不同子類實現以便獲取不同類型的語句連接,子類可以普通執行 SQL 語句,也可以做預編譯執行,還可以執行存儲過程等。

  • SimpleStatementHandler:普通語句處理器,繼承 BaseStatementHandler 抽象類,對應 java.sql.Statement 對象的處理,處理普通的不帶動態參數運行的 SQL,即執行簡單拼接的字符串語句,同時由于 Statement 的特性,SimpleStatementHandler 每次執行都需要編譯 SQL (注意:我們知道 SQL 的執行是需要編譯和解析的)。

  • PreparedStatementHandler:預編譯語句處理器,繼承 BaseStatementHandler 抽象類,對應 java.sql.PrepareStatement 對象的處理,相比上面的普通語句處理器,它支持可變參數 SQL 執行,由于 PrepareStatement 的特性,它會進行預編譯,在緩存中一旦發現有預編譯的命令,會直接解析執行,所以減少了再次編譯環節,能夠有效提高系統性能,并預防 SQL 注入攻擊(所以是系統默認也是我們推薦的語句處理器)。

  • CallableStatementHandler:存儲過程處理器,繼承 BaseStatementHandler 抽象類,對應 java.sql.CallableStatement 對象的處理,很明了,它是用來調用存儲過程的,增加了存儲過程的函數調用以及輸出/輸入參數的處理支持。

其實普通語句處理器、預執行語句處理器以及存儲過程處理器,只是 Mybatis 對于 JDBC 的語句執行對象的簡單包裝而已,沒有特別神秘,看以下 JDBC 的語句執行對象的類圖關系也就能夠清楚。

  • RoutingStatementHandler:路由語句處理器,直接實現了 StatementHandler 接口,作用如其名稱,確確實實只是起到了路由功能,并把上面介紹到的三個語句處理器實例作為自身的委托對象而已,所以執行器在構建語句處理器時,都是直接 new 了 RoutingStatementHandler 實例。

// 1、執行器構建語句處理器實例
public StatementHandler newStatementHandler(...) {
   
    
    // 構建路由語句處理器即可!
    StatementHandler statementHandler = 
        new RoutingStatementHandler(...);
    
    // 其它邏輯忽略...
    return statementHandler;
}

// 2、實際構造方法(路由關系)
public RoutingStatementHandler(...) {
   

    // 根據指定類型構造委托實例
    switch (ms.getStatementType()) {
   
      case STATEMENT:
        delegate = new SimpleStatementHandler(...);
        break;
      case PREPARED:
        delegate = new PreparedStatementHandler(...);
        break;
      case CALLABLE:
        delegate = new CallableStatementHandler(...);
        break;
      default:
        throw new ExecutorException(
            "Unknown statement type: " 
                + ms.getStatementType());
    }
}

我們前面介紹了執行器具體執行 CRUD 操作時,構造的語句處理器默認使用 PrepareStatementHandler ,不過有些好奇的腦袋就想問問,那我們能不能指定語句處理器類型呢?

當然可以,例如我們指定更新用戶語句適用預編譯處理語句處理器:

<!--取值范圍 STATEMENT, PREPARED, CALLABLE -->
<update id="updateUser" statementType="STATEMENT">
    update t_user set name = #{newName}
</update>

當 Mybatis 在解析映射器中的每條語句時,會設置語句處理器類型:

// 語句對象解析器 
public class XMLStatementBuilder {
   
    
    // 解析語句節點
    public void parseStatementNode() {
    
        
        // 設置語句處理器類型
        // 默認是 PREPARED 類型
        StatementType statementType = 
         StatementType.valueOf(
            context.getStringAttribute(
                "statementType", 
                StatementType.PREPARED.toString()
            )
        ); 
    }  
}

所以,語句執行器與數據庫的交互過程:

Mybatis最硬核的API是什么

當然,語句處理器接口 StatementHandler 提供了基本接口,一般我們沒必要自定義實現類,所以可以簡單看一下即可:

Mybatis最硬核的API是什么

Mybatis最硬核的API是什么

9、ParamerHandler – 參數處理器

ParameterHandler 是一個參數處理器接口,它負責把用戶傳遞的參數轉換成 JDBC Statement 所需要的參數,底層做數據轉換的工作會交給類型轉換器 TypeHandler,后面會介紹。

很顯然,需要對傳入的參數進行轉換處理的 StatementHandler 實例只有兩個,分別是:

  • PrepareStatementHandler 預編譯處理器

  • CallableStatementHandler 存儲過程處理器

上面在介紹語句處理器的時候,我們有介紹說基礎語句處理器 BaseStatementHandler 在進行實例構建時,會同時構建參數處理器與結果集處理器,所以參數處理器就是在此時被構建。

// 基礎語句處理器
public abstract class BaseStatementHandler{
   
    
    // 構造實例時
    protected BaseStatementHandler(...){
   
        
        // 其它邏輯可忽略...
        
        // 1、構建參數處理器
        this.parameterHandler = 
            conf.newParameterHandler(...);
    	
        // 2、構建結果集處理器
        this.resultSetHandler = 
        	conf.newResultSetHandler(...);
    } 
}

對于參數處理器接口,相對簡單,只有1個默認實現類 DefaultParameterHandler ,該接口只有兩個方法,分別是:

Mybatis最硬核的API是什么

  • 1、setParameters 設置參數,發生在 CURD 語句執行時,語句處理器設置參數

// 有2個處理器會使用,分別是:
// 預編譯處理器 PreparedStatementHandler
// 存儲過程處理器 CallableStatementHandler

public void parameterize(Statement statement) {
   
    
    //使用ParameterHandler對象來完成對Statement的設值
    parameterHandler.setParameters(statement);
}

應用場景例如查詢用戶對象時,設置姓名,參數處理器結合類型處理器把 name 屬性占位符進行賦值。

<select id="queryUSer">
    select * from t_user where name = #{name}
</select>
  • 2、getParameterObject 獲取參數,發生在結果集返回時,結果集處理器獲取對象參數,值得注意的時,該方法只用于存儲過程處理器 CallableStatementHandler 。

// 默認結果集處理器
public class DefaultResultSetHandler{
   
   
    // 處理輸出參數
    public void handleOutputParameters(...) {
   
    
        // 獲取參數
        final Object parameterObject = 
            parameterHandler.getParameterObject();
    
    	// 其它存儲過程輸出參數處理邏輯...
	}    
}

Mybatis最硬核的API是什么

10、ResultSetHandler – 結果集處理器

ResultSetHandler 是一個結果集處理器接口,它負責負責將 JDBC 返回的結果集 resultSet 對象轉換為 List 類型的集合,是在語句處理器構建實例時被同時創建,底層做數據轉換的工作會交給類型轉換器 TypeHandler,它有1個默認實現類 DefaultResultSetHandler,該接口有3個方法,分別是:

Mybatis最硬核的API是什么

  • handleResultSets:負責結果集處理,完成映射返回結果對象

  • handleCursorResultSets :負責游標對象處理

  • handleOutputParameters :負責存儲過程的輸出參數處理

結果集處理器對于 JDBC 返回的結果集的基本處理,是先獲取我們在映射器 Mapper 中指定 resultType 或 resultMap 映射關系,然后遍歷解析結果集中的每一列數據,底層通過 MetaObject 對象做相關的反射處理。

對于詳細的源碼邏輯,我們后續源碼剖析部分詳細講。

不講不是中國人 O(∩_∩)O ~

Mybatis最硬核的API是什么

11、TypeHandler – 類型轉換器

TypeHandler 是一個類型轉換器/處理器接口,它負責 Java 數據類型和 JDBC 數據類型之間的映射與轉換,當對 Statement 對象設置參數時,由 JavaType 轉換為 JdbcType,當對 Statement 返回結果集進行封裝映射時,又會將 JdbcType 轉換為 JavaType。

Mybatis最硬核的API是什么

一般,我們可以直接使用 Mybatis 內置的類型處理器,簡單看了一下有 65+ 個,當然我們是可以根據業務需要自定義類型處理器的,以便處理復雜類型或非標類型。

具體做法為:

1、實現 org.apache.ibatis.type.TypeHandler 接口;

2、繼承 org.apache.ibatis.type.BaseTypeHandler 類。

其中 BaseTypeHandler 類作為抽象類就已經實現了 TypeHandler 接口。

我們看到接口 TypeHandler 定義了四個方法:

public interface TypeHandler<T> {
   

  // 設置參數
  void setParameter(
      PreparedStatement ps, 
      int i, T parameter, 
      JdbcType jdbcType);

  // 根據列名獲取轉換結果
  T getResult(ResultSet rs, String columnName);

  // 根據列下標獲取轉換結果
  T getResult(ResultSet rs, int columnIndex);

  // 根據列下標獲取【存儲過程】的輸出結果
  T getResult(CallableStatement cs, int columnIndex);

}

其實,我之前在介紹 Mybatis 核心配置的時候,有大力介紹過類型處理器,沒必要重復寫(其實是懶),感興趣的朋友可以直接看我們之前的文章 **《Mybatis系列全解(四):全網最全!Mybatis配置文件XML全貌詳解》**中對類型處理器 TypeHandler 的介紹。

Mybatis最硬核的API是什么

12、MappedStatement – 語句對象

MappedStatement 語句對象,就是我們在映射器 Mapper 中維護的每一條語句,例如 <select|update|delete|insert>,Mybatis 中通過語句構造器 XMLStatementBuilder 對每一個語句進行解析:

Mybatis最硬核的API是什么

整個解析過程分為4步驟:

  • 1、配置解析器 XMLConfigBuilder 解析映射器:

// Configuration 配置解析器
public class XMLConfigBuilder{
   
    
    // 解析映射器
    private void mapperElement(){
   
        
        // 創建映射器解析實例
        XMLMapperBuilder mapperParser = 
            new XMLMapperBuilder(...);
        
        // 開始解析
        mapperParser.parse();
    }
}

2、映射對象解析器 XMLMapperBuilder 解析語句

// 映射對象解析器
public class XMLMapperBuilder{
   
    
    // 1、解析入口
    public void parse() {
    
        
        // 解析映射器文件
        configurationElement(
            parser.evalNode("/mapper"));
    }
    
    // 2、節點解析
    private void configurationElement(XNode context) {
   
        
        // 構建語句對象
        buildStatementFromContext(
            context.evalNodes(
                "select|insert|update|delete"));
    }
    
    // 3、最終調用語句解析器
    private void buildStatementFromContext(){
   
        
        // 創建語句解析實例
        XMLStatementBuilder statementParser = 
            new XMLStatementBuilder();
        
        // 解析語句節點
        statementParser.parseStatementNode();
    }
}

3、語句解析器 XMLStatementBuilder 解析每一個節點

// 語句解析器
public class XMLStatementBuilder{
   
    
    // 解析語句節點
    public void parseStatementNode() {
   
        
        // 通過語句輔助類構建語句對象
        builderAssistant.addMappedStatement(...)
    }
}

4、語句輔助類 MapperBuilderAssistant 添加進語句集合中

// 語句輔助類
public class MapperBuilderAssistant{
   
    
    // 添加語句對象
    public MappedStatement addMappedStatement(
         
        // 最終添加到配置類的語句集合中
    	configuration.addMappedStatement(statement);
    }
}

Mybatis最硬核的API是什么

13、SqlSource – SQL源

SqlSource 是一個 SQL 源接口,它會結合用戶傳遞的參數對象 parameterObject,動態地生成 SQL 語句,并最終封裝成 BoundSql 對象。SqlSource 接口有5個實現類,分別是:StaticSqlSource、DynamicSqlSource、RawSqlSource、ProviderSqlSource、VelocitySqlSource(這只是一個測試用例,而非真正模板 Sql 源實現類)。

Mybatis最硬核的API是什么

  • StaticSqlSource:靜態 SQL 源實現類,所有的 SQL 源最終都會構建 StaticSqlSource 實例,該實現類會生成最終可執行的 SQL 語句供 statement 或 prepareStatement 使用。

  • RawSqlSource:原生 SQL 源實現類,解析構建含有 ‘#{}’ 占位符的 SQL 語句或原生 SQL 語句,解析完最終會構建 StaticSqlSource 實例。

  • DynamicSqlSource:動態 SQL 源實現類,解析構建含有 ‘${}’ 替換符的 SQL 語句或含有動態 SQL 的語句(例如 If/Where/Foreach等),解析完最終會構建 StaticSqlSource 實例。

  • ProviderSqlSource:注解方式的 SQL 源實現類,會根據 SQL 語句的內容分發給 RawSqlSource 或 DynamicSqlSource ,當然最終也會構建 StaticSqlSource 實例。

  • VelocitySqlSource:模板 SQL 源實現類,官方申明這只是一個測試用例,而非真正的模板 Sql 源實現類。

SqlSource 實例在配置類 Configuration 解析階段就被創建,Mybatis 框架會依據3個維度的信息來選擇構建哪種數據源實例:

  • 第一個維度:客戶端的 SQL 配置方式:XML 方式或者注解方式。

  • 第二個維度:SQL 語句中是否使用動態 SQL ( if/where/foreach 等 )。

  • 第三個維度:SQL 語句中是否含有替換符 ‘${}’ 或占位符 ‘#{}’ 。

SqlSource 接口只有一個方法 getBoundSql ,就是創建 BoundSql 對象。

public interface SqlSource {
   

  BoundSql getBoundSql(Object parameterObject);

}

Mybatis最硬核的API是什么

14、BoundSql – SQL語句

BoundSql 對象存儲了動態生成的 SQL 語句以及相應的參數信息,BoundSql 對象是在執行器具體執行 CURD 時通過實際的 SqlSource 實例所構建。通過 BoundSql 能夠獲取到實際數據庫執行的 SQL 語句,系統可根據 SQL 語句構建 Statement 或者 PrepareStatement 。

public class BoundSql {
   

  //該字段中記錄了SQL語句,該SQL語句中可能含有"?"占位符
  private final String sql;
    
  //SQL中的參數屬性集合
  private final List<ParameterMapping> parameterMappings;
    
  //客戶端執行SQL時傳入的實際參數值
  private final Object parameterObject;
    
  //復制 DynamicContext.bindings 集合中的內容
  private final Map<String, Object> additionalParameters;
    
  //通過 additionalParameters 構建元參數對象
  private final MetaObject metaParameters;
    
}

到此,相信大家對“Mybatis最硬核的API是什么”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

浙江省| 凤山市| 阿克陶县| 措勤县| 涞水县| 精河县| 河源市| 东台市| 巴里| 易门县| 房产| 甘洛县| 棋牌| 丰台区| 汤原县| 屏山县| 潜江市| 巫山县| 商洛市| 康乐县| 凉城县| 东乌珠穆沁旗| 大城县| 白山市| 神池县| 高清| 万盛区| 冕宁县| 绩溪县| 石景山区| 安陆市| 盘山县| 灵川县| 大庆市| 石楼县| 开封县| 繁峙县| 安义县| 叙永县| 肇州县| 霍山县|