在了解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
- 通過XMLConfigBuilder(org.apache.ibatis.builder.xml)解析配置的XML文件,讀出配置參數(shù),并將讀取的數(shù)據(jù)存入Configuration(org.apache.ibatis.session)對象中。
- 使用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運行流程圖如下

SqlSession是通過Executor創(chuàng)建StatementHandler來運行的,而StatementHandler要經(jīng)過下面三步:
- prepared預(yù)編譯SQL
- parameterize設(shè)置參數(shù)
- 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í)行過程