上篇文章講了mybatis是怎麼創建SqlSessionFactory的:mybatis源碼解析-SqlsessionFactory,簡單來說就是通過構造模式讀取xml配置文件封裝到Configuration
對象中,返回一個默認的DefaultSqlSessionFactory
對象,需要注意的是我們寫的每一個mapper映射文件在配置類中定義好了之後會被解析進Configuration
中,並且mapper映射文件中的增刪改查標籤都有與之對應的MappedStatement
對象封裝,我們還是擺出hello world來演示:
//1.通過輸入流解析xml配置文件
InputStream inputstream = Resources.getResourceAsStream("xxx.xml")
SqlsessionFactory sqlsessionfactory = new SqlsessionFactoryBuilder().build(inputstream);
//2.獲取和數據庫的鏈接,創建會話
SqlSession openSession = sqlsessionfactory.openSession();
//3.獲取接口的實現類對象,會爲接口自動的創建一個代理對象mapper,代理對象會去執行增刪改查方法
xxxMapper mapper = openSession.getMapper(xxxMapper.class)
//4.執行增刪改的方法
第一步已經講過了,現在來看第二步,獲取鏈接創建會話SqlSession
Sqlsession
1.1:直接來到sqlsessionfactory.openSession();
這個方法,它其實調用的是DefaultSqlSessionFactory
的openSessionFromDataSource
方法
public SqlSession openSession(boolean autoCommit) {
return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, autoCommit);
}
在進入查看這個方法之前,this.configuration.getDefaultExecutorType()
這個是選擇一種執行器
這裏默認選的是SIMPLE,在mybatis官方文檔有這樣的三種設置:
1.2:好了,進入openSessionFromDataSource
這個方法:
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
DefaultSqlSession var8;
try {
Environment environment = this.configuration.getEnvironment();
TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
Executor executor = this.configuration.newExecutor(tx, execType);
var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
} catch (Exception var12) {
this.closeTransaction(tx);
throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12);
} finally {
ErrorContext.instance().reset();
}
return var8;
}
首先根據configuration
獲取當前環境,配置事務信息,Executor executor = this.configuration.newExecutor(tx, execType);
這裏根據我們選擇的執行器類型創建執行器,進入newExecutor
方法:
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? this.defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Object executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
if (this.cacheEnabled) {
executor = new CachingExecutor((Executor)executor);
}
Executor executor = (Executor)this.interceptorChain.pluginAll(executor);
return executor;
}
那麼什麼是Executor
呢?請往下看:
這個接口裏的方法就是我們執行增刪改查的方法,我們繼續走,在newExecutor
方法中有這樣一段代碼:
if (this.cacheEnabled) {
executor = new CachingExecutor((Executor)executor);
}
它的意思是判斷cacheEnabled
是否開啓也就是我們configuration
全局配置中是否開啓二級緩存,如果開啓就用CachingExecutor((Executor)executor)
來包裝這個執行器,我們進入這個類:
1.3:我們截取一部分代碼來研究:
public class CachingExecutor implements Executor {
private final Executor delegate;
private final TransactionalCacheManager tcm = new TransactionalCacheManager();
public CachingExecutor(Executor delegate) {
this.delegate = delegate;
delegate.setExecutorWrapper(this);
}
來看一看這個類的結構:、
我們可以知道,這個類將傳進來的執行器包裝了一下,真正執行增刪改查的是他內部的Executor delegate
對象,我們繼續看newExecutor
在最終完成並返回Executor
前,還會調用這個方法:
Executor executor = (Executor)this.interceptorChain.pluginAll(executor);
就是調用攔截器鏈的pluginAll方法,在目前爲止這個方法看起來貌似沒什麼作用,其實不然,在後面的插件介紹中,它就通過這種方式來包裝我們的執行器,我們來看一下這個方法:
public Object pluginAll(Object target) {
Interceptor interceptor;
for(Iterator var2 = this.interceptors.iterator(); var2.hasNext(); target = interceptor.plugin(target)) {
interceptor = (Interceptor)var2.next();
}
return target;
}
很簡單,調用所有的攔截器來對Executor進行封裝,好了,到現在我們就把Executor封裝完畢了,回到1.2的openSessionFromDataSource
這個方法:
Executor executor = this.configuration.newExecutor(tx, execType);
var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
return var8;
將executor
傳入了DefaultSqlSession
中,來看一下這個類:
最終返回了DefaultSqlSession
總結
最後用一張圖來簡單回顧一下: