1. 程式人生 > >MyBatis執行原理(二)SqlSession物件建立過程分析

MyBatis執行原理(二)SqlSession物件建立過程分析

在上一篇博文中分析了SqlSessionFactory物件建立的過程,有了SqlSessionFactory物件工廠就可以建立SqlSession了,下面就來具體分析一下SqlSession物件建立的過程。

一、SqlSession物件建立過程分析

入口程式:

    private SqlSessionFactory getSqlSessionFactory() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream is = Resources.getResourceAsStream(resource);

        return
new SqlSessionFactoryBuilder().build(is); } @Test public void testMyBatis3Simple() throws IOException { SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); // 將斷點打在下面程式碼的前面 SqlSession sqlSession = sqlSessionFactory.openSession(); }

1.首先會跳到DefaultSqlSessionFactory

類中的openSession()方法中。

    // ====== DefaultSqlSessionFactory 類中的方法 ======

  @Override
  public SqlSession openSession() {
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
  }

在上面這個方法中呼叫了另一個方法:
openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit)

,這個方法做了些什麼呢?下面我們就來追蹤一下。

  // ====== DefaultSqlSessionFactory 類中的方法 ======

  private SqlSession openSessionFromDataSource(ExecutorType execType, 
                              TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      // 獲取配置環境中的一些資訊,用於建立事務
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      /**
      * ExecutorType 是一個列舉型別,預設是SIMPLE
      * 根據ExecutorType 建立一個Executor 物件
      * 因為Executor 物件比較重要,下面來分析一下Executor 物件建立的過程
      */
      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();
    }
  }

2.configuration.newExecutor(tx, execType)建立過程如下:

  // ====== Configuration 類中的方法 ======

  public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    /**
    * 根據executorType 型別建立對應的Executor 
    * BatchExecutor:批量執行器
    * ReuseExecutor:會執行預處理的執行器
    * SimpleExecutor:簡單的執行器
    */
    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);
    }
    /**
    * 如果開啟了二級快取,則使用CachingExecutor 來包裝executor,
    * 在查詢之前都會先查詢快取中是否有對應的資料
    * 包裝的過程使用了裝飾者模式,裝飾者模式可參考博文:
    * http://blog.csdn.net/codejas/article/details/79112824
    */
    if (cacheEnabled) {
      executor = new CachingExecutor(executor);
    // 最後使用每個攔截器重新包裝executor 並返回
    executor = (Executor) interceptorChain.pluginAll(executor);
    // executor 物件建立完成並返回
    return executor;
  }

3.Executor 物件建立完成後,會接著執行
openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit)方法。

  // ====== DefaultSqlSessionFactory 類中的方法 ======

  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      final Executor executor = configuration.newExecutor(tx, execType);
      /**
       * configuration 物件在建立SqlSessionFactory 物件的時候就已經建立了
       * Executor 物件建立完成後,使用executor與configuration 物件來建立DefaultSqlSession
       * 返回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();
    }
  }

到這裡會接著向上一步返回,SqlSession物件建立的過程也就結束了。

呼叫過程時序圖:
這裡寫圖片描述

二、總結

這篇博文對sqlSessionFactory建立SqlSession物件的過程進行了原始碼分析,最後返回的SqlSession中包含有兩個重要的物件,分別是configurationexecutorconfiguration物件在建立SqlSessionFactory的時候就已經被創建出來了,用來儲存全域性配置檔案與SQL 對映檔案中的資訊,executor是一個執行器物件。如果你想了解更多的細節,可以自己檢視原始碼,希望這篇博文能夠為你提供幫助。