MyBatis運行原理分析

在了解MyBatis的運行流程前,先快速了解下MyBatis的四大核心組件,MyBatis的整個執(zhí)行流程都是圍繞這四個組件進行的。

  • SqlSessionFactoryBuilder(構(gòu)造器),會根據(jù)配置信息或者代碼來生成SqlSessionFactory(工廠接口)
  • SqlSessionFactory,用來生成SqlSession(會話)
  • SqlSession,是一個既可以發(fā)送SQL去執(zhí)行并返回結(jié)果,也可以獲取Mapper的接口
  • SQL Mapper,由一個Java接口和XML文件(或注解)構(gòu)成的,需要給出對應(yīng)的SQL和映射規(guī)則,它負責(zé)發(fā)送SQL去執(zhí)行,并返回結(jié)果

MyBatis的運行分為兩部分

  • 第一部分是讀取配置文件緩存到Configuration對象,用來創(chuàng)建SqlSessionFactory
  • 第二部分是SqlSession的執(zhí)行過程
    下面將詳細分析這兩部分

構(gòu)建SqlSessionFactory

  1. 通過XMLConfigBuilder(org.apache.ibatis.builder.xml)解析配置的XML文件,讀出配置參數(shù),并將讀取的數(shù)據(jù)存入Configuration(org.apache.ibatis.session)對象中。
  2. 使用Configuration對象去創(chuàng)建SqlSessionFactory,SqlSessionFactory是一個接口,MyBatis提供了一個默認實現(xiàn)類DefaultSqlSessionFactory(org.apache.ibatis.session.defaults),大部分場景下都不需自己創(chuàng)建SqlSessionFactory實現(xiàn)類

SQLSession運行過程

構(gòu)建SqlSessionFactory就可以拿到SqlSession,SqlSession提供了增、刪、查、改方法,在舊版本的MyBatis或iBatis中基本是直接使用這些方法,在新版本中則是建議使用Mapper,其中Mapper映射是通過動態(tài)代理來實現(xiàn)的

SqlSession的四大對象

Mapper映射器通過動態(tài)代理對象進入到MapperMethed的execute方法,經(jīng)過簡單判斷就可以進入增、刪、查、改等方法,然后Mapper的執(zhí)行過程是通過Executor、StatementHandler、ParameterHandler和ResultHandler來完成數(shù)據(jù)庫操作和結(jié)果返回。

Executor

代表執(zhí)行器,由它來調(diào)度StatementHandler、ParameterHandler、ResultHandler等來執(zhí)行對應(yīng)的SQL,是一個真正執(zhí)行Java和數(shù)據(jù)庫交互的東西,有三種執(zhí)行器,可以通過setting元素中的defaultExecutorType來配置
1. SIMPLE,簡易執(zhí)行器,也是默認的執(zhí)行器
2. REUSE,重用預(yù)處理語句
3. BATCH,執(zhí)行重用語句和批量更新,是針對批量專用的執(zhí)行器

StatementHandler

使用數(shù)據(jù)庫的Statement(PrepardStatement)執(zhí)行操作,它是四大對象的核心,起承上啟下的作用,StatementHandler是專門處理數(shù)據(jù)庫會話,Configuration生成StatementHandler會話器的邏輯如下

  public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
  
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
    
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return statementHandler;
  }

其中RoutingStatementHandler是StatementHandler的一個具體實現(xiàn),但不是我們使用的真實對象,它是通過適配模式找到對應(yīng)的StatementHandler來執(zhí)行的,主要分為三種
1. SimpleStatementHandler直接使用普通的Statement對象,這樣每次執(zhí)行SQL語句都需要數(shù)據(jù)庫對SQL進行預(yù)編譯
2. PreparedStatementHandler使用PrepareStatement執(zhí)行,雖然初次創(chuàng)建PrepareStatement時開銷比較大,但在多次處理SQL時只需要初始化一次,可以有效提高性能
3. CallableStatementHandler使用CallableStatement執(zhí)行,CallableStatement是用來執(zhí)行存儲過程的
各模式執(zhí)行查詢的流程類似,都是實現(xiàn)三個主要方法prepare、parameterize和query

ParameterHandler

用于SQL對參數(shù)的處理ParameterHandler(org.apache.ibatis.executor.parameter)的接口定義如下

public interface ParameterHandler {
  Object getParameterObject();
  void setParameters(PreparedStatement ps)
      throws SQLException;
}

默認提供了DefaultParameterHandler實現(xiàn)類
1. getParameterObject返回參數(shù)對象
2. setParameters設(shè)置預(yù)編譯SQL語句的參數(shù),主要是從parameterObject對象中取參數(shù),然后使用typeHandler進行參數(shù)處理,typeHandler是注冊在Configuration里

ResultHandler

是進行最后數(shù)據(jù)集(ResultSet)的封裝返回處理,ResultSetHandler(org.apache.ibatis.executor.resultset)的接口定義如下

public interface ResultSetHandler {
  <E> List<E> handleResultSets(Statement stmt) throws SQLException;
  <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;
  void handleOutputParameters(CallableStatement cs) throws SQLException;
}

默認提供了一個實現(xiàn)類DefaultResultSetHandler,實現(xiàn)比較復(fù)雜,會涉及Javassist或者CGLIB作為延遲加載,然后通過typeHandler和ObjectFactory進行組裝結(jié)果再返回。
1. handleOutputParameters是處理存儲過程輸出參數(shù)的
2. handleResultSets是封裝結(jié)果集的
3. handleCursorResultSets是封裝批處理結(jié)果集

SqlSession運行流程圖如下


MyBatis SqlSession運行流程

SqlSession是通過Executor創(chuàng)建StatementHandler來運行的,而StatementHandler要經(jīng)過下面三步:

  1. prepared預(yù)編譯SQL
  2. parameterize設(shè)置參數(shù)
  3. query/update執(zhí)行SQL
    其中parameterize是調(diào)用parameterHandler的方法去設(shè)置的,而參數(shù)是根據(jù)類型處理器typeHandler去處理的,query/update方法是通過ResultHandler進行處理結(jié)果的封裝,如果是update語句,就返回整數(shù),否則通過typeHandler處理結(jié)果類型,然后用ObjectFactory提供的規(guī)則組裝對象,返回給調(diào)用者。這就是SqlSession的主要執(zhí)行過程
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容