Mybatis精講(二)—生命周期
目錄
回顧
-
上一章節我們通過xml和代碼的方式實現了Mybatis環境的配置。代碼方式只是簡單介紹下。我們也知道我們大部分情況使用的是xml方式的配置。在實際開發中我們那樣開發顯然是不合理的。
-
上章節提到的組件显示不可能每次執行sql都要重新創建的。這樣性能上肯定是過不去的。今天我們就來簡單聊聊SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession、Mapper這些組件的生命周期吧。
SqlSessionFactoryBuilder
- 通過觀察分析這個類我們就知道既然是Builder模式的類,那他的作用就是構建起(孵化器).換句話說這個類不是那麼的重要,因為他唯一的作用就是孵化SqlSessionFactory。在Spring與Mybatis整合的框架中,我相信Spring一定是在構建了SqlSessionFactory之後就將這個類進行回收了。因為後面就不需要了。這裏純屬個人猜想。
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
- 上面就是我們通過加載xml配置文件的源碼。我們不難發現build核心是通過XMLConfigBuilder這個類去負責解析mybatis-config.xml配置文件並生成Configuration對象。
SqlSessionFactory
- 看名字就知道是工廠模式。在這裏我們可以把他看成數據庫連接池。既然是工廠就肯定得有產品。SqlSessionFactory的產物就是SqlSession。SqlSession是與數據庫的一次連接。管理數據庫的連接的自然就是連接池了。
- Mybatis中使用的SqlSessionFactory是
DefaultSqlSessionFactory
。 以連接池的角度看待我們不難推斷出SqlSessionFactory應該是個單例 。SqlSessionFactory對應的是數據庫。一個數據庫原則上應該對應一個SqlSessionFactory來管理。這點在Spring中正好無縫連接。把SqlSessionFactory交由spring管理。spring默認是單例模式bean.
openSessionFromDataSource
- SqlSessionFactory通過openSession方法獲取SqlSession.SQLSession實際上可以看做是一次數據庫的連接。下面我們通過源碼的方式去看看工廠是如何生產SqlSession的。
<!--定義數據庫信息,默認使用development數據庫構建環境-->
<environments default="development">
<environment id="development">
<!--jdbc事物管理-->
<transactionManager type="JDBC"></transactionManager>
<!--配置數據庫連接信息-->
<dataSource type="POOLED">
<property name="driver" value="${database.driver}"/>
<property name="url" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
</dataSource>
</environment>
</environments>
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
//定義一個事物對象
Transaction tx = null;
try {
//通過配置對象獲取事先配置好的環境對象 這裏對應了xml中的environments標籤 。environments默認develop.所以是develop的environment
final Environment environment = configuration.getEnvironment();
//通過環境獲取事物。在environment里配置了JDBC類型的事物==JdbcTransactionFactory;如果沒有配置則默認採用ManagedTransactionFactory
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
//構建事物對象 , 實際就是屬性的賦值
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//獲取執行器 BatchExecutor、ReuseExecutor、SimpleExecutor , 選擇SimpleExecutor
//因為默認有緩存,這裡會用CachingExecutor包裹原始Executor , 之後會加載各種插件
final Executor executor = configuration.newExecutor(tx, execType);
//返回DefaultSqlSession。寫死
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();
}
}
Executor
- Mybatis的數據庫執行器。Mybatis提供了一共四中Executor.這裏嚴格意義上應該說是三種 BatchExecutor、ReuseExecutor、SimpleExecutor。還有一個CachingExecutor。這裏為什麼不把他算上了。因為這個是一個全局的開關。在settings標籤的cacheEnabled設置的。說道這個標籤大家都知道這個就是二級緩存的開關。所以這裏CachingExecutor就不做介紹了。
- SimpleExecutor是一種常規執行器,每次執行都會創建一個statement,用完后關閉。
- ReuseExecutor是可重用執行器,將statement存入map中,操作map中的statement而不會重複創建statement。
- BatchExecutor是批處理型執行器,doUpdate預處理存儲過程或批處理操作,doQuery提交並執行過程。
- 關於Executor的選取也是在settings標籤控制的。defaultExecutorType。 默認是simple
SqlSession
- 每個線程都有一個屬於自己的Sqlsession對象。這裏我們看成是一次Connection。他的生命周期應該是一次完成的事物處理過程。他是一個線程不安全的對象。在多線程操作的時候我們需要注意事物的隔離級別。我們操作時需要注意的是每次處理玩需要將他關閉。否則會造成資源浪費。在Mybaits中已經通過finnally把我們將他釋放了。
Mapper
- Mapper是一個接口,我們可以將xml看成他的一個實現類。這裏的實現類虛化。通過Java代碼的調用實際將xml對應的sql發送給數據庫並獲取數據結果。
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
- 通過上述代碼我們能夠發現。在獲取Mapper的時候先通過類型看是否被註冊了。然後根據類別獲取代理實例。
總結
- 關於生命周期其實沒什麼重點。這一章節也比較簡單。我們只需要知道我們最終需要的Mapper。然後是如何從配置到獲取Mapper.這過程中哪些是全局的。哪些又適合做成復用的。
# 加入戰隊
微信公眾號
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※專營大陸空運台灣貨物推薦
※台灣空運大陸一條龍服務