1. 程式人生 > >mybatis 查詢執行原理(原始碼解析)

mybatis 查詢執行原理(原始碼解析)

從sqlsessionfactory.openSession處得到session之後,這個session是defaultSqlSession

private static SqlSessionFactory sqlSessionFactory = null;

       /**

        * 初始化Session工廠

        *

        * @throws IOException

        */

       private static void initialFactory() throws IOException {

             String resource = "mybatis-config.xml";

             InputStream inputStream = Resources.getResourceAsStream(resource);

             sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

       }

       /**

        * 獲取Session

        *

        * @return

        */

       public static SqlSession getSession() {

             if (sqlSessionFactory == null) {

                    try {

                           initialFactory();

                    } catch (IOException e) {

                           e.printStackTrace();

                    }

             }

             return sqlSessionFactory.openSession(true);

       }

呼叫selectList方法,在selectList中呼叫executor.query方法

@Override

  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {

    try {

      MappedStatement ms = configuration.getMappedStatement(statement);

      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();

    }

  }

這個executor 是CachingExecutor(在初始化sqlsession中Configuration 已經初始化過了)

Configuration.class

protected boolean cacheEnabled = true;

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {

    executorType = executorType == null ? defaultExecutorType : executorType;

    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;

    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);

    }

    if (cacheEnabled) {

      executor = new CachingExecutor(executor);

    }

    executor = (Executor) interceptorChain.pluginAll(executor);

    return executor;

  }

CachingExecutor 類中獲取BoundSql,生成快取key,在第二個query方法中判斷是否快取命中,否則執行delegate.<E> query

@Override

  public <E> List<E> 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 <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)

      throws SQLException {

    Cache cache = ms.getCache();

    if (cache != null) {

      flushCacheIfRequired(ms);

      if (ms.isUseCache() && resultHandler == null) {

        ensureNoOutParams(ms, parameterObject, boundSql);

        @SuppressWarnings("unchecked")

        List<E> list = (List<E>) tcm.getObject(cache, key);

        if (list == null) {

          list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);

          tcm.putObject(cache, key, list); // issue #578 and #116

        }

        return list;

      }

    }

    return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);

  }

執行BaseExecutor.query方法,再呼叫queryFromDatabase方法

@Override

  public <E> List<E> 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<E> list;

    try {

      queryStack++;

      list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;

      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;

  }

queryFromDatabase方法中呼叫doQuery方法執行查詢

 private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {

    List<E> list;

    localCache.putObject(key, EXECUTION_PLACEHOLDER);

    try {

      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;

  }

doQuery是抽象方法,由子類完成重寫,這裡呼叫的是SimpleExecutor類,也是在sqlsession初始化中初始化的

@Override

  public <E> List<E> 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);

      stmt = prepareStatement(handler, ms.getStatementLog());

      return handler.<E>query(stmt, resultHandler);

    } finally {

      closeStatement(stmt);

    }

  }

這裡用到了一個設計模式:裝飾器模式(同一個實現介面或者同一個繼承類,在子類A中呼叫子類B中的方法),也是單一原則的體現(每一個類專注於一件事情)

呼叫prepareStatement方法,parameterize方法中使用parameterHandler 完成set引數動作

 private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {

    Statement stmt;

    Connection connection = getConnection(statementLog);

    stmt = handler.prepare(connection, transaction.getTimeout());

    handler.parameterize(stmt);

    return stmt;

  }

 @Override

  public void parameterize(Statement statement) throws SQLException {

    parameterHandler.setParameters((PreparedStatement) statement);

  }

呼叫query方法,使用java.sql.prepareStatement 查詢資料,最後使用resultSetHandler 封裝結果集,返回List<Object>

@Override

  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {

    PreparedStatement ps = (PreparedStatement) statement;

    ps.execute();

    return resultSetHandler.<E> handleResultSets(ps);

  }

//封裝結果集

 @Override

  public List<Object> handleResultSets(Statement stmt) throws SQLException {

    ErrorContext.instance().activity("handling results").object(mappedStatement.getId());

    final List<Object> multipleResults = new ArrayList<Object>();

    int resultSetCount = 0;

    ResultSetWrapper rsw = getFirstResultSet(stmt);

    List<ResultMap> resultMaps = mappedStatement.getResultMaps();

    int resultMapCount = resultMaps.size();

    validateResultMapsCount(rsw, resultMapCount);

    while (rsw != null && resultMapCount > resultSetCount) {

      ResultMap resultMap = resultMaps.get(resultSetCount);

      handleResultSet(rsw, resultMap, multipleResults, null);

      rsw = getNextResultSet(stmt);

      cleanUpAfterHandlingResultSet();

      resultSetCount++;

    }

    String[] resultSets = mappedStatement.getResultSets();

    if (resultSets != null) {

      while (rsw != null && resultSetCount < resultSets.length) {

        ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);

        if (parentMapping != null) {

          String nestedResultMapId = parentMapping.getNestedResultMapId();

          ResultMap resultMap = configuration.getResultMap(nestedResultMapId);

          handleResultSet(rsw, resultMap, null, parentMapping);

        }

        rsw = getNextResultSet(stmt);

        cleanUpAfterHandlingResultSet();

        resultSetCount++;

      }

    }

    return collapseSingleResultList(multipleResults);

  }