我們處於的位置
我們要清楚現在的情況.
現在我們已經調用了SqlSessionFactoryBuilder
的build方法生成了SqlSessionFactory
對象.
但是如標題所說,要想生成sqlsession
還要另一步SqlSessionFactory
調用openSession()
方法生成sqlsession
;
這就要從上一部分代碼講起
上文講到
我們創建的實際上是一個叫做DefaultSqlSessionFactory
的類,實際上他是一個SqlSessionFactory
接口(沒錯,這玩應是接口)的實現類.
既然sqlsession是由opensession產生的,那我們就先看這個方法.
說一嘴題外話就是自動提交也是在這個部分設置的,下面是如果你設置了autocommit的情況.
public SqlSession openSession(boolean autoCommit) {
//this.configuration.getDefaultExecutorType()值為 ExecutorType.SIMPLE;
return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, autoCommit);
}
參數中 configuration 獲取了默認的執行器 “SIMPLE”.
DefaultSqlSessionFactory
類
調用了一個同一個類中openSessionFromDataSource
方法.
在這個類中是如下執行流程
所要知道的一部分知識.
environments運行環境
MyBatis 核心配置綜述之 Configuration詳解
其實就是數據庫連接那個部分.
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
//從configuration對象中得到環境配置的對象
final Environment environment = configuration.getEnvironment();
//這個對象被用來創建一個事務工廠->一號分支
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
//事務工廠創建一個事務對象->二號分支
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//而 configurationye 則會根據事務對象和執行器類型創建一個執行器。
->三號分支
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();
}
}
現在我們要從一號分支開始
一號分支
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
這個代碼如下:
我們發現有兩種可能性.
如果傳進來的值沒有設置 標籤那麼他會執行 ManagedTransactionFactory()
而反之則會執行 environment.getTransactionFactory()
這兩者產生的對象都實現了 TransactionFactory
接口.
這裏ManagedTransactionFactory()
是沒有標籤時生成的對象.其核心就是一句
private boolean closeConnection = true;
的屬性.
我們不必過於關注這個部分.
private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
if (environment == null || environment.getTransactionFactory() == null) {
//如果沒有目標標籤
return new ManagedTransactionFactory();
}
//如果有目標標籤
return environment.getTransactionFactory();
}
environment.getTransactionFactory()
產生的東西才是重點.
調用環境對象的getTransactionFactory
方法,該方法和我們配置的一樣返回了一個 JdbcTransactionFactory
,而實際上,TransactionFactory
只有2個實現類,一個是 ManagedTransactionFactory
(沒有標籤時返回的),一個是 JdbcTransactionFactory
(有標籤時返回的)。
至此一號分支結束,從此看來,一號分支實際上是將environment對象包裝成一個工廠對象.
請返回一號分支之前部分繼續.
分支二
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
我們回到openSessionFromDataSource
方法,獲取了 JdbcTransactionFactory
后,調用 JdbcTransactionFactory
的newTransaction
方法創建一個事務對象.
當然因為代碼中採用TransactionFactory
接口作為聲明對象.所以無論分之一傳回來的是哪個工廠對象.在分支二中都可以執行.
我們先講 JdbcTransactionFactory
的情況.
分支二中調用的是這個newTransaction
方法.(還有一個重載的)
public Transaction newTransaction(Connection conn) {
return new JdbcTransaction(conn);
}
這就到了另一個類中JdbcTransaction
中.
JdbcTransaction
我刪掉其中的實現代碼
public class JdbcTransaction implements Transaction {
private static final Log log = LogFactory.getLog(JdbcTransaction.class);
protected Connection connection;
protected DataSource dataSource;
protected TransactionIsolationLevel level;
protected boolean autoCommmit;
public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
dataSource = ds;
level = desiredLevel;
autoCommmit = desiredAutoCommit;
}
public JdbcTransaction(Connection connection) {
this.connection = connection;
}
public Connection getConnection() throws SQLException {
}
public void commit() throws SQLException {
}
public void rollback() throws SQLException {
}
public void close() throws SQLException {
}
protected void setDesiredAutoCommit(boolean desiredAutoCommit) {
}
protected void resetAutoCommit() {
}
protected void openConnection() throws SQLException {
}
}
其實只要看了代碼你就會發現,這個類中的方法,和我們調用session的方法高度重合.比如commit,rollback等等.而且還能設置事務的隔離級別
所以我們有理由認為,這個類就是對jdbc連接部分的封裝.
總結
至此分支二結束,我們對於 標籤在xml中的存在情況,會返回兩種截然不同對象.一種是作為jdbc連接封裝的 JdbcTransaction
對象.另一個則是 ManagedTransaction
對象(這個沒講….)
分支三
第三分支我們將回到Configuration
對象.
Configuration對象
法此時已經創建好事務對象。接下來將事務對象執行器作為參數執行 configuration 的 newExecutor 方法來獲取一個 執行器類。我們看看該方法實現:
首先第一句將判斷是否傳入了一個excutorType參數,如果沒有就用默認的參數.
也就是 ExecutorType.SIMPLE(前面出現過),然後根據執行的類型來創建不同的執行器,默認是 SimpleExecutor 執行器.
Mybatis有三種基本的Executor執行器:
-
SimpleExecutor:每執行一次update或select,就開啟一個Statement對象,用完立刻關閉Statement對象。
-
ReuseExecutor:執行update或select,以sql作為key查找Statement對象,存在就使用,不存在就創建,用完后,不關閉Statement對象,而是放置於Map<String, Statement>內,供下一次使用。簡言之,就是重複使用Statement對象。
-
BatchExecutor:執行update(沒有select,JDBC批處理不支持select),將所有sql都添加到批處理中(addBatch()),等待統一執行(executeBatch()),它緩存了多個Statement對象,每個Statement對象都是addBatch()完畢后,等待逐一執行executeBatch()批處理。與JDBC批處理相同。
作用範圍:Executor的這些特點,都嚴格限制在SqlSession生命周期範圍內。
然後我們看下一句部分
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);
}
我們先將 BatchExecutor執行器.
該類包裝了事務對象,延遲加載的隊列,本地緩存,永久緩存,配置對象,還包裝了自己。
傳入的兩個參數分別為存儲了配置信息的Configuration對象,以及封裝了jdbc中連接數據庫部分代碼的
JdbcTransaction
對象.
回到 newExecutor 方法,判斷是否使用緩存,默認是true, 則將剛剛的執行器包裝到新的 CachingExecutor 緩存執行器中。最後將執行器添加到所有的攔截器中(如果配置了話),我們這裏沒有配置。
到此分支三結束
總結:
我們從用從分支二得到的對象,構建了一個執行器.這個執行對象,包括事務對象(即連jdbc連接部分的控制封裝.JdbcTransaction
),延遲加載的隊列,本地緩存,永久緩存,配置對象(Configuration),還包裝了自己。
四號分支
我們已經有了執行器,此時創建 DefaultSqlSession 對象,攜帶 configuration, executor, autoCommit 三個參數,該構造器就是簡單的賦值過程。我們有必要看看該類的結構:
該類包含了常用的所有方法,包括事務方法,可以說,該類封裝了執行器和事務類。而執行器才是具體的執行工作人員。
至此,我們已經完成了 SqlSession 的創建過程。
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※為什麼 USB CONNECTOR 是電子產業重要的元件?
※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!
※台北網頁設計公司全省服務真心推薦
※想知道最厲害的網頁設計公司"嚨底家"!
※推薦評價好的iphone維修中心