[Mybatis]Mybatis動作フロー分析

15955 ワード

機会がMybatisに注目しているので、本論文ではMybatisの全体的な実行プロセスを探ってみます.
Mybatisの例
    InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
    SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    SqlSessionFactory factory = builder.build(inputStream);

    SqlSession sqlSession = factory.openSession();
    sqlSession.selectList("selectAllUser");

    sqlSession.close();
Mybatisは上のように、前の3行のコードはスキャンxmlの情報を登録して、後のために使用するべきです.私達が重点的に注目しているのは中間の2行です.これらはどうやって完全なクエリを実現しますか?上記のfactoryはデフォルトでDefault Sql Session Factoryというカテゴリーです.このようにSql Sessionを作成します.SQL操作はSql Sessionで実行されます.
Sql Session Factory
このインターフェースのデフォルトの実装クラスはDefault Sql Session Factoryです.
public class DefaultSqlSessionFactory implements SqlSessionFactory {

  private final Configuration configuration;//    

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

  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);
      //     Executor,   SimpleExecutor,SqlSession    Executor   SQL 。
      final Executor executor = configuration.newExecutor(tx, execType);
      //  Executor    SqlSession。
      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();
    }
  }

}
Sql Session
このインターフェースのデフォルトの実装クラスはDefault Sql Sessionで、上で生成されたSql Sessionはこのクラスのオブジェクトです.
public class DefaultSqlSession implements SqlSession {

  private Configuration configuration;
  // executor CachingExecutor,      executor     SQL ,     executor         ,           ,mybatis            
  private Executor executor;

  private boolean autoCommit;//      
  private boolean dirty;

  @Override
  public  List selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
      //       MappedStatement  ,MappedStatement     SQL     ,
      MappedStatement ms = configuration.getMappedStatement(statement);
      // MappedStatement       CachingExecutor  
      return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

}
Exector
Mybatisの実行コアは、Exectorにあり、いくつかの実装クラスがあり、一括実行などは、このインターフェースで実現されるものであり、本稿では、SimpleExectorの全体的な実装クラスのみに注目して、簡単なクエリである.
本当のSimpleExectorを呼び出す前に、MybatisはCachingExectorをも呼び出しました.コードは以下の通りです
public class CachingExecutor implements Executor {//     ,         。
  //       SimpleExecutor,          
  private Executor delegate;
  private TransactionalCacheManager tcm = new TransactionalCacheManager();

  @Override
  public  List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    BoundSql boundSql = ms.getBoundSql(parameterObject);
    CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
    return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

  @Override
  public  List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
      throws SQLException {
    //   CachingExecutor       ,        ,        ,      。          
    Cache cache = ms.getCache();// ms    
    if (cache != null) {//             
      flushCacheIfRequired(ms);
      if (ms.isUseCache() && resultHandler == null) {
        ensureNoOutParams(ms, parameterObject, boundSql);
        @SuppressWarnings("unchecked")
        List list = (List) tcm.getObject(cache, key);
        if (list == null) {
          list = delegate. query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
          tcm.putObject(cache, key, list); // issue #578 and #116
        }
        return list;
      }
    }
    //              
    return delegate. query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

}
上記の分析ではSQLの実行は最終的にはSimpleExectorによって実行されることを知っています.SimpleExectorの構造を見てください.
org.apache.ibatis.executor.Executor
    org.apache.ibatis.executor.BaseExecutor
        org.apache.ibatis.executor.SimpleExecutor
BaseExectorは抽象的なタイプで、Exectorインターフェースを実現しました.
public abstract class BaseExecutor implements Executor {

  @SuppressWarnings("unchecked")
  @Override
  public  List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
    if (closed) {
      throw new ExecutorException("Executor was closed.");
    }
    if (queryStack == 0 && ms.isFlushCacheRequired()) {
      clearLocalCache();
    }
    List list;
    try {
      queryStack++;
      list = resultHandler == null ? (List) localCache.getObject(key) : null;
      //      ,          CacheExecutor   ,       。
      if (list != null) {
        handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
      } else {//             
        list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
      }
    } finally {
      queryStack--;
    }
    if (queryStack == 0) {
      for (DeferredLoad deferredLoad : deferredLoads) {
        deferredLoad.load();
      }
      // issue #601
      deferredLoads.clear();
      if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
        // issue #482
        clearLocalCache();
      }
    }
    return list;
  }

 //       
  private  List queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    List list;
    localCache.putObject(key, EXECUTION_PLACEHOLDER);
    try {
      //    ,doQuery()         ,      。
      list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
    } finally {
      localCache.removeObject(key);
    }
    localCache.putObject(key, list);
    if (ms.getStatementType() == StatementType.CALLABLE) {
      localOutputParameterCache.putObject(key, parameter);
    }
    return list;
  }

  //    ,               
  protected abstract  List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
      throws SQLException;  

}
サブクラスのSimpleExectorを見てください.これがクエリーの真の実装クラスです.
public class SimpleExecutor extends BaseExecutor {

  @Override
  public  List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      //          Statement
      stmt = prepareStatement(handler, ms.getStatementLog());
      //    stmt,   Statement   query()   。
      return handler.query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }


  private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    Connection connection = getConnection(statementLog);
    stmt = handler.prepare(connection);
    handler.parameterize(stmt);
    return stmt;
  }

}
最後にSimpleStation Handlerを見て、どうやってクエリが実現されますか?
public class SimpleStatementHandler extends BaseStatementHandler {

  @Override
  public  List query(Statement statement, ResultHandler resultHandler) throws SQLException {
    String sql = boundSql.getSql();//      SQL
    statement.execute(sql);//              ,    ,    jdbc    。
    return resultSetHandler.handleResultSets(statement);
  }

}
本論文では、Mybatis全体の動作手順を迅速に理解するために、exectorインターフェースのような多くの実装クラスが省略されています.この文では一つしか与えられていません.