Mybatis詳解(二) sqlsession的創建過程

Mybatis詳解(二) sqlsession的創建過程

我們處於的位置

我們要清楚現在的情況.

現在我們已經調用了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 后,調用 JdbcTransactionFactorynewTransaction方法創建一個事務對象.

當然因為代碼中採用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維修中心