1. 程式人生 > >MyBatis的解析和執行原理---學習筆記(三)

MyBatis的解析和執行原理---學習筆記(三)

官方文件

執行分兩大部分

1.讀取配置檔案,快取到Configuration物件中,用來建立SqlSessionFactory

2.SqlSession執行過程

動態代理:JDK反射機制和CGLIB代理。用於為Mapper產生代理類,執行相關方法。

反射呼叫的最大好處是配置性大大提高,降低模組之間耦合

JDK動態代理
必須提供介面
代理類要求實現InvocationHandler介面
/* 
 * Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);//bind 產生代理物件
 * Object result = method.invoke(target,args);//反射呼叫方法

 */

CGLIB動態代理,開源框架CGLIB
代理類需要實現MethodInterceptor介面
/* 
 * //getInstance
 * Enhancer enhancer = new Enhancer();
 * enhancer.setSuperClass(this.target.getClass());
 * enhancer.setCallback(this);//設定回撥方法
 * enhancer.create();//建立代理物件
 *
 * //intercept
 * Object result = proxy.invokeSuper(obj,args);//反射呼叫方法
 */
MyBatis通常在延遲載入的時候才會用到CGLIB的動態代理


構建SqlSessionFactory
採用構造模式(降低物件的複雜性),通過SqlSessionFactoryBuilder進行構建
a)通過XMLConfigBuilder解析XML配置,讀取資料存入Configuration類中(單例,幾乎所有配置都存在這裡)

b)使用Configuration物件建立SqlSessionFactory. (使用DefaultSqlSessionFactory)

對映器內部組成
a)MappedStatement,儲存對映器的一個節點(select|insert|delete|update)
b)SqlSource,提供BoundSql物件,是MappedStatement的一個屬性,主要作用:根據引數和其他規則組裝SQL

c)BoundSql,建立SQL和引數,常用屬性SQL,parameterObject,parameterMappings

parameterObject:傳遞簡單物件 如int->Integer,傳遞多個引數{ “1”:p1,"2":p2..."param1":p1,"param2":p2...}
parameterMappings:是一個List,每個元素都是ParamterMapping物件,包含屬性、名稱、表示式、javaType、jdbcType、typeHandler等
SQL:寫在對映器裡面的SQL語句

sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

SqlSession包含查詢、插入、更新、刪除方法,舊版中常用,新版中推薦使用Mapper

Mapper對映是通過動態代理來實現的
MapperProxy<T> implements InvocationHandler,Serializable {....
if(Object.class.equals(method.getDeclaringClass())) {//判斷mapper是不是一個類
  return method.invoke(this,args);
}
final MapperMethod = cachedMapperMethod(method);//如果是介面,生成MapperMethod物件
return mapperMethod.execute(sqlSession,args);//執行SQL,insert/update/delete/select

對映器的XML名稱空間對應的是Mapper介面類的全路徑
根據全路徑,利用動態代理,採用命令模式,使用SqlSession介面的方法執行SQL查詢


Mapper執行過程元件(SqlSession四大物件)
Executor,執行器,負責排程StatementHandler、ParameterHandler、ResultHandler等來執行對應的SQL
StatementHandler,核心,使用Statement(PrepareStatement)執行SQL
ParameterHandler,處理SQL引數
ResultHandler,對結果集(ResultSet)進行封裝,並返回

Executor提供了查詢/更新/相關的事務方法
a)SIMPLE,簡易執行器,預設,new SimpleExecutor(this,transaction);
b)REUSE,重用預處理語句,new ReuseExecutor(this,transaction);
c)BATCH,針對批量專用的執行器,批量更新/重用語句,new BatchExecutor(this,transaction);
new CachingExecutor(executor);
interceptorChain.pluginAll(executor);//通過外掛構建一層層的動態代理物件


SqlSession執行總結
SqlSession通過Executor建立StatementHandler
StatementHandler(通過RoutingStatementHandler--->(使用SimpleStatementHandler, PreparedStatementHandler, CallableStatement )),然後執行下面三個步驟:a)prepared預編譯SQL 
b)parameterize設定引數(啟用ParameterHandler,實現類DefaultParameterHandler)

c)query/update執行SQL(啟用ResultSetHandler,實現類DefaultResultSetHandler)

parameterize呼叫parameterHandler的setParameters方法去設定引數,而引數根據型別處理器typeHandler進行處理.
query/update是通過ResultHandler的handleResult方法封裝結果,如果是update,它返回整數,否則就通過typeHandler處理結果型別,最後呼叫ObjectFactory組裝物件並返回.