1. 前言
上篇說到,建構了DefaultSqlSessionFactory,這一節,繼續一探究竟。
2. 正文
老規矩,先上案例。
2.1 案例
@Test
public void test(){
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();@1
PersonDao personDao = sqlSession.getMapper(PersonDao.class);
Person p = new Person();
p.setAddress("廣東省");
p.setAge(12);
p.setEmail("[email protected]");
p.setName("chen");
p.setPhone("15345634565");
personDao.insert(p);@4
System.out.println(p.toString());
sqlSession.commit();
sqlSession.close();
}
@1根據得到的SqlSessionFactory ,打開一個session,下面一起進入到裡面,看下裡面具體的邏輯
2.2 DefaultSqlSessionFactory#openSession
DefaultSqlSessionFactory#openSession
@Override
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);@1
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
if (environment == null || environment.getTransactionFactory() == null) {
return new ManagedTransactionFactory();
}
return environment.getTransactionFactory();
}
首先,這裡設定了預設的執行器類型:configuration.getDefaultExecutorType(),事務隔離級别傳入了null。
@1 TransactionFactory是接口,有2個實作類,分别是JdbcTransactionFactory、ManagedTransactionFactory,根據目前環境,擷取事務管理工廠,如果環境為空或者沒有配置事務工廠,則用預設的ManagedTransactionFactory,否則就調用你mybatis-config.xml中配置的,我這裡配置了JDBC,并且在解析的時候,已經set到Environment中了,是以,直接調用environment.getTransactionFactory()就可以擷取到了。下面介紹下這2中類型的差別
2.3 JdbcTransaction和ManagedTransaction的差別
到這裡,是不是先看下這2個事務工廠的差別。這裡的差別,主要是JdbcTransaction和ManagedTransaction的差別, 這2個類都實作了Transaction接口,接口了定義了幾個方法,大家經常見到這幾個。
Mybatis管理事務是分為兩種方式:
(1)使用JDBC的事務管理機制,就是利用java.sql.Connection對象完成對事務的送出
(2)使用MANAGED的事務管理機制,這種機制mybatis自身不會去實作事務管理,而是讓程式的容器(JBOSS,WebLogic)來實作對事務的管理
仔細看:
ManagedTransaction#commit、rollback、getTimeout都是空的。隻負責打開和關閉連接配接。
其實,JDBC 是mybatis 幫我們實作了事務管理,當然這個活,也可以交由其它程式的容器(JBOSS,Weblogic)來實作。
繼續回到DefaultSqlSession#openSessionFromDataSource中
final Executor executor = configuration.newExecutor(tx, execType);
execType 是前面傳入的預設的執行器類型,即ExecutorType.SIMPLE。
下一步,進newExecutor 方法
2.4 Configuration#newExecutor
mybatis的執行器有三種類型:
ExecutorType.SIMPLE 這個類型不做特殊的事情,它隻為每個語句建立一個PreparedStatement。
ExecutorType.REUSE 這種類型将重複使用PreparedStatements。
ExecutorType.BATCH 這個類型批量更新,且必要地差別開其中的select 語句,確定動作易于了解。
Configuration#newExecutor
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor 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);@1
}
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
executor = (Executor) interceptorChain.pluginAll(executor);@2
return executor;
}
InterceptorChain#pluginAll
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}
根據executorType不同的類型,建構相應的執行器,但cacheEnabled 預設是true,是以,這裡傳回CachingExecutor執行器
@2 從配置插件裡面取出插件對象(通過jdk動态代理來擷取對象),mybatis裡插件用到了責任鍊的設計模式。
繼續傳回DefaultSqlSessionFactory#openSessionFromDataSource 方法
得到了執行器,直接new 一個DefaultSqlSession,接着來看下DefaultSqlSession ,構造函數的參數有配置、執行器、dirty(false 表示記憶體中的資料和資料庫中一緻), 是否自動送出=false參數。
public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
this.configuration = configuration;
this.executor = executor;
this.dirty = false;
this.autoCommit = autoCommit;
}
裡面有常用的一些查詢方法
到這裡,我們就擷取到Session, 下一篇,重點介紹裡面的重要方法。
3. 總結
3.1 通過上面的功能,我們擷取到了session,session是我們與資料庫溝通的橋梁
3.2 通過session 可以擷取到系統中的mapper 代理對象,下一篇就是介紹如何擷取的。
4. 參考
[1] https://blog.csdn.net/meiwen1111/article/details/8260387
[2] https://blog.csdn.net/qq_36074042/article/details/74206611