MyBatis整合Spring-->SqlSession獲取

目的java

MyBatis在執行SQL語句時,都須要建立一個SqlSession,可是這裏還須要與Spring的事務進行整合,那麼SqlSession是怎麼建立的呢?下面就來分析一下。sql

上一章節已經分析MapperProxy代理類中,具體執行代碼,實際MyBatis調用就是使用的SqlSession入口,就來看看SqlSession具體是哪一個類。數據庫

經過DEBUG,可知是SqlSessionTemplate類。session

根據前一章節的查詢來分析,上圖就是SqlSessionTemplate類的查詢方法,就來看一下sqlSessionProxy屬性。app

根據SqlSessionTemplate類的構造器能夠看出,sqlSessionProxy屬性是一個代理類爲SqlSessionInterceptor,看一下代理類的回調方法。spa

明顯這裏有獲取SqlSession,這應該就是DefaultSqlSession,來看看,是怎麼獲取到的?.net

public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
    notNull(sessionFactory, "No SqlSessionFactory specified");
    notNull(executorType, "No ExecutorType specified");
    // 使用Spring來獲取資源
    SqlSessionHolder holder = (SqlSessionHolder) getResource(sessionFactory);
    // 已存在SqlSessionHolder,直接獲取
    if (holder != null && holder.isSynchronizedWithTransaction()) {
      if (holder.getExecutorType() != executorType) {
        throw new TransientDataAccessResourceException("Cannot change the ExecutorType when there is an existing transaction");
      }
      holder.requested();
      if (logger.isDebugEnabled()) {
        logger.debug("Fetched SqlSession [" + holder.getSqlSession() + "] from current transaction");
      }
      return holder.getSqlSession();
    }
    if (logger.isDebugEnabled()) {
      logger.debug("Creating a new SqlSession");
    }
    // 新建SqlSession 
    SqlSession session = sessionFactory.openSession(executorType);
    // Register session holder if synchronization is active (i.e. a Spring TX is active)
    //
    // Note: The DataSource used by the Environment should be synchronized with the
    // transaction either through DataSourceTxMgr or another tx synchronization.
    // Further assume that if an exception is thrown, whatever started the transaction will
    // handle closing / rolling back the Connection associated with the SqlSession.
    if (isSynchronizationActive()) {
      Environment environment = sessionFactory.getConfiguration().getEnvironment();
      if (environment.getTransactionFactory() instanceof SpringManagedTransactionFactory) {
        if (logger.isDebugEnabled()) {
          logger.debug("Registering transaction synchronization for SqlSession [" + session + "]");
        }
        // 與Spring綁定
        holder = new SqlSessionHolder(session, executorType, exceptionTranslator);
        bindResource(sessionFactory, holder);
        registerSynchronization(new SqlSessionSynchronization(holder, sessionFactory));
        holder.setSynchronizedWithTransaction(true);
        holder.requested();
      } else {
        if (getResource(environment.getDataSource()) == null) {
          if (logger.isDebugEnabled()) {
            logger.debug("SqlSession [" + session + "] was not registered for synchronization because DataSource is not transactional");
          }
        } else {
          throw new TransientDataAccessResourceException(
              "SqlSessionFactory must be using a SpringManagedTransactionFactory in order to use Spring transaction synchronization");
        }
      }
    } else {
      if (logger.isDebugEnabled()) {
        logger.debug("SqlSession [" + session + "] was not registered for synchronization because synchronization is not active");
      }
    }
    return session;
  }

這裏就是獲取當前的事務裏的SqlSession,並與Spring綁定。debug

DefaultSqlSessionFactory工廠的openSession方法。代理

DefaultSqlSessionFactory工廠的openSessionFromDataSource方法。首先獲取環境信息,獲取事務工廠(SpringManagedTransactionFactory),這個就是在MyBatis整合Spring的實現(1)中4.6建立的。還有Executor也是代理對象,把MyBatis中的配置的攔截器代理進來,這個之後再分析。code

根據數據源(DataSource)建立了一個SpringManagedTransaction事務。

上圖能夠發現,這是個代理對象,最後new DefaultSqlSession對象。

最後經過方法反射調用DefaultSqlSession類的下圖方法。

總結

MyBatis的SqlSession是在Dao層獲取的,Service層只是Spring管理了事務,Dao層MyBatis經過與Spring的整合,來使用Spring的事務,因此目前的配置與Spring的整合,只能支持默認的SIMPLE類型(每次執行一個SQL都須要數據庫編譯),若是須要使用BATCH(批量新增,只需編譯一次SQL,本次添加的SQL都按編譯時的SQL來進行添加),這樣明顯提高效率。批量時,也想使用Spring的事務管理,就須要擴展SqlSession,這裏之後再分析。

相關文章
相關標籤/搜索