Mybatis源码笔记(六)、ResultHandler

ResultHandler 接口比较简单,主要用于处理 ResultContext 对象

public interface ResultHandler<T> {

  void handleResult(ResultContext<? extends T> resultContext);

}

ResultHandler 主要有两个实现,分别是 DefaultResultHandler 和 DefaultMapResultHandler

  @SuppressWarnings("unchecked")
  public DefaultMapResultHandler(String mapKey, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
    this.objectFactory = objectFactory;
    this.objectWrapperFactory = objectWrapperFactory;
    this.reflectorFactory = reflectorFactory;
    this.mappedResults = objectFactory.create(Map.class);
    this.mapKey = mapKey;
  }

  @Override
  public void handleResult(ResultContext<? extends V> context) {
    final V value = context.getResultObject();
    final MetaObject mo = MetaObject.forObject(value, objectFactory, objectWrapperFactory, reflectorFactory);
    // TODO is that assignment always true?
    final K key = (K) mo.getValue(mapKey);
    mappedResults.put(key, value);
  }

  public Map<K, V> getMappedResults() {
    return mappedResults;
  }
}

public class DefaultResultHandler implements ResultHandler<Object> {

  private final List<Object> list;

  public DefaultResultHandler() {
    list = new ArrayList<>();
  }

  @SuppressWarnings("unchecked")
  public DefaultResultHandler(ObjectFactory objectFactory) {
    list = objectFactory.create(List.class);
  }

  @Override
  public void handleResult(ResultContext<?> context) {
    list.add(context.getResultObject());
  }

  public List<Object> getResultList() {
    return list;
  }

}

区别的化一目了然,DefaultMapResultHandler 将处理结果存储在一个 Map 对象中,DefaultResultHandler 将结果存储在一个 List 对象中。

总结:

至此,我们的主线流程大致的也就有了一些了解,对应于传统的 JDBC 方式,我们一步一步地分析了源码,他们是如何运作的,基本上已经明了了。实际上mybatis的框架还是很复杂的,其中一些很复杂的逻辑我们并没有实际深入,比如boundSql的解析,自动填充对象的映射,等等。想要有更深的了解还需进一步精度这些代码。

Mybatis源码笔记(五)、ResultSetHandler

StatementHandler 返回的结果主要是通过 ResultSetHandler 接口来处理,BaseStatementHandler 的构造方法中有如下代码初始化 StatementHandler,返回的是 StatementHandler 的实现类

 this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);```
 通过configration的newResultSetHandler返回ResultSetHandler对象。

   public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
      ResultHandler resultHandler, BoundSql boundSql) {
        // 这里返回的是DefaultResultSetHandler对象
    ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
    resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
    return resultSetHandler;
  }
   // DefaultResultSetHandler实现了ResultSetHandler
  public class DefaultResultSetHandler implements ResultSetHandler {
    ......
  }

ResultSetHandler 接口的方法如下

public interface ResultSetHandler {

  <E> List<E> handleResultSets(Statement stmt) throws SQLException;

  <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;

  void handleOutputParameters(CallableStatement cs) throws SQLException;

}

我们来开下 DefaultResultSetHandler 的具体实现

  @Override
  public List<Object> handleResultSets(Statement stmt) throws SQLException {
    ErrorContext.instance().activity("handling results").object(mappedStatement.getId());

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

    int resultSetCount = 0;
    // 获取第一个结果集处理
    ResultSetWrapper rsw = getFirstResultSet(stmt);

// 从mappedStatement获取解析出的ResultMaps
    List<ResultMap> resultMaps = mappedStatement.getResultMaps();
    int resultMapCount = resultMaps.size();
    // 判断是否设置了resultMap或resultSet
    validateResultMapsCount(rsw, resultMapCount);
    // 处理返回结果resultMap
    while (rsw != null && resultMapCount > resultSetCount) {
      ResultMap resultMap = resultMaps.get(resultSetCount);
      handleResultSet(rsw, resultMap, multipleResults, null);
      rsw = getNextResultSet(stmt);
      cleanUpAfterHandlingResultSet();
      resultSetCount++;
    }

    // 通过mappedStatement获取多结果集数组对象
    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);
  }


    //处理结果集
    private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
    try {
      if (parentMapping != null) {
        handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
      } else {
        // 如果resultHandler为空,构建一个对象去处理
        if (resultHandler == null) {
          DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
            // 处理结果集行数据
          handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
          multipleResults.add(defaultResultHandler.getResultList());
        } else {
          handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
        }
      }
    } finally {
      // issue #228 (close resultsets)
      closeResultSet(rsw.getResultSet());
    }
  }

  // 通过ResultHandler处理result
  public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
    if (resultMap.hasNestedResultMaps()) {
      ensureNoRowBounds();
      checkResultHandler();
      handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
    } else {
        // 处理简单映射
      handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
    }
  }


    private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
      throws SQLException {
    DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
    ResultSet resultSet = rsw.getResultSet();
    skipRows(resultSet, rowBounds);
    while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
      ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
        // 获取行记录
      Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
        //通过resultHandler操作存储结果
      storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
    }
  }
// 行记录的处理
  private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
    final ResultLoaderMap lazyLoader = new ResultLoaderMap();
    //  创建返回的result映射对象
    Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
    if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
      final MetaObject metaObject = configuration.newMetaObject(rowValue);
      boolean foundValues = this.useConstructorMappings;
        // 是否需要自动映射
      if (shouldApplyAutomaticMappings(resultMap, false)) {
          // 该方法完成自动映射,逻辑很是很复杂的,具体的不深究
        foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
      }
      foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
      foundValues = lazyLoader.size() > 0 || foundValues;
      rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
    }
    return rowValue;
  }

  private void storeObject(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue, ResultMapping parentMapping, ResultSet rs) throws SQLException {
    if (parentMapping != null) {
      linkToParents(rs, parentMapping, rowValue);
    } else {
      callResultHandler(resultHandler, resultContext, rowValue);
    }
  }
// resultHandler处理结果
  @SuppressWarnings("unchecked" /* because ResultHandler<?> is always ResultHandler<Object>*/)
  private void callResultHandler(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue) {
    resultContext.nextResultObject(rowValue);
    ((ResultHandler<Object>) resultHandler).handleResult(resultContext);
  }

至此,我们可以清晰地看到 ResultSetHandler 根据 mappedStatement 中设置的 ResultMap来处理 statement 执行返回的结果,处理映射的逻辑写的还是很精彩的,考虑的比较全面。

下一节,我们将看下 ResultHandler 是如何处理存储返回的 rowValue 的。

Mybatis源码笔记(四)、StatementHandler

在上一节中我们看到,Statement 处理主要由 StatementHandler 接口实现,StatementHandler 由 configuration.newStatementHandler 创建

 StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.update(stmt);


public StatementHandler newStatementHandler(Executor executor,
MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return statementHandler;
  }

//   根据 不同的类型创建不同的StatementHandler
    public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {

    switch (ms.getStatementType()) {
      case STATEMENT:
        delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case PREPARED:
        delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case CALLABLE:
        delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      default:
        throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
    }

  }

我们看一下 StatementHandler 接口的方法

public interface StatementHandler {

Statement prepare(Connection connection, Integer transactionTimeout)
throws SQLException;

void parameterize(Statement statement)
throws SQLException;

void batch(Statement statement)
throws SQLException;

int update(Statement statement)
throws SQLException;

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

<E> Cursor<E> queryCursor(Statement statement)
throws SQLException;

BoundSql getBoundSql();

ParameterHandler getParameterHandler();

}

我们选取其中的 SimpleStatementHandler 来具体分析下,SimpleStatementHandler 继承了 BaseStatementHandler,BaseStatementHandler 实现了 StatementHandler 接口


public abstract class BaseStatementHandler implements StatementHandler { // 配置 protected final Configuration configuration; protected final ObjectFactory objectFactory; protected final TypeHandlerRegistry typeHandlerRegistry; //结果处理 protected final ResultSetHandler resultSetHandler; //参数处理 protected final ParameterHandler parameterHandler; // 具体的执行器 protected final Executor executor; // mappedStatement protected final MappedStatement mappedStatement; ...... } // 继承实现类SimpleStatementHandler public class SimpleStatementHandler extends BaseStatementHandler { ...... @Override public int update(Statement statement) throws SQLException { // 执行SQL String sql = boundSql.getSql(); // SQL param Object parameterObject = boundSql.getParameterObject(); // 主键生成方式 KeyGenerator keyGenerator = mappedStatement.getKeyGenerator(); int rows; // 根据不同的keyGenerator,传入 不同的参数执行,最后返回结果 if (keyGenerator instanceof Jdbc3KeyGenerator) { // 很熟悉的味道 statement.execute(sql, Statement.RETURN_GENERATED_KEYS); rows = statement.getUpdateCount(); keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject); } else if (keyGenerator instanceof SelectKeyGenerator) { statement.execute(sql); rows = statement.getUpdateCount(); keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject); } else { statement.execute(sql); rows = statement.getUpdateCount(); } // 返回结果 return rows; } ...... }

上面的 update 方法我们终于找到了熟悉的东西,JDBC 的 statement 执行,至此,一切都清楚了。其实万变不离其宗,只是框架让我们可以脱离一些低级、重复劳动,优化性能,比我们自己徒手实现的要好。但是归根结底还是基础,所以基础还是要打牢的。

Mybatis源码笔记(三)、Executor

闲言少叙,书接上文,上一节我们读到 session 的执行,这一节我们来看下 Executor。Executor 也是一个接口,我们来大致看一下这个接口

public interface Executor {
ResultHandler NO_RESULT_HANDLER = null;

int update(MappedStatement ms, Object parameter) throws SQLException;

<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;

<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;

<E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;

List<BatchResult> flushStatements() throws SQLException;

void commit(boolean required) throws SQLException;

void rollback(boolean required) throws SQLException;

CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);

boolean isCached(MappedStatement ms, CacheKey key);

void clearLocalCache();

void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);

Transaction getTransaction();

void close(boolean forceRollback);

boolean isClosed();

void setExecutorWrapper(Executor executor);
}

在前面章节的 openSession 中我们介绍了 Executor 的创建,主要包含如下三种 Executor,分别是批量 BatchExecutor、复用 ReuseExecutor、以及简单 SimpleExecutor,默认是 SimpleExecutor。

// 获取Executor
  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;
  }

我们可以发现,这三种 Executor 都继承了抽象类 BaseExecutor

public class BatchExecutor extends BaseExecutor {
 ......
}
public class ReuseExecutor extends BaseExecutor {
 ......
}
public class SimpleExecutor extends BaseExecutor {
 ......
}

我们继续追踪到 Executor,我们看看上一节的 update 实现

public abstract class BaseExecutor implements Executor {
......
// Executor的wrapper对象,如果开启缓存,那么会创建Executor的代理CachingExecutor,
// 通过delegate.setExecutorWrapper(this)将CachingExecutor设置进来,后期的缓存操作就委托给了子类,
// 由于mybatis本身的实现问题,在分布式环境下有可能会存在脏数据问题,所以开启缓存是要注意
  protected Executor wrapper;
 ......


  @Override
  public int update(MappedStatement ms, Object parameter) throws SQLException {
    ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
    if (closed) {
      throw new ExecutorException("Executor was closed.");
    }
    clearLocalCache();
    // 最终进入到doUpdate方法
    return doUpdate(ms, parameter);
  }

// 抽象方法,具体的继承类实现
    protected abstract int doUpdate(MappedStatement ms, Object parameter)
      throws SQLException;

}

上述代码可以看到,具体的操作其实是委托给子类进行处理的。看一下具体的实现

public class SimpleExecutor extends BaseExecutor {

  public SimpleExecutor(Configuration configuration, Transaction transaction) {
    // 调用父类构造函数
    super(configuration, transaction);
  }

  @Override
  public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
    Statement stmt = null;
    try {
    // 获取配置
      Configuration configuration = ms.getConfiguration();
    //   获取handler
      StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
      stmt = prepareStatement(handler, ms.getStatementLog());
    //   交由handler执行
      return handler.update(stmt);
    } finally {
      closeStatement(stmt);
    }
  }
  ......
}

总结:

这一节我们主要看了 Executor 极其实现,鉴于篇幅,我们选取了其中一个方法来说明,其实还是很简单的。下一节我们将看下 Statement 是如何执行的。

Mybatis源码笔记(二)、SqlSession

书接前文,我们这一节来看看 SqlSession。


// SqlSession 是 mybatis 主要的接口之一,通过这个接口, // 我们可以实现执行命令,获取 mappers,以及事务的管理 public interface SqlSession extends Closeable { ...... }

该接口的方法大致如下,有了这些方法,我们就可以进行各种操作了
sqlSession
上一节中,我们通过 SqlSessionFactoryBean 的 buildSqlSessionFactory 方法获得到了 DefaultSqlSessionFactory。下面我们来看下是如何通过 SqlSessionFactory 获得 SqlSession 的,我们取其中的一个例子。


@Override public SqlSession openSession() { return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false); } private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; try { // 获取Environment,Environment对象中有TransactionFactory和DataSource对象, // 使用经典的建造者模式,通过链式调用返回创建。 final Environment environment = configuration.getEnvironment(); // 通过environment 获取transactionFactory,来创建transaction, // 这里的autoCommit为false,即默认不自动提交。 final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); // 根据不同的执行类型获取Executor执行器 final Executor executor = configuration.newExecutor(tx, execType); // 这一步,创建了SqlSession的一个实现类DefaultSqlSession, // 这样我们就获取到了SqlSession return new DefaultSqlSession(configuration, executor, autoCommit); } catch (Exception e) { // 异常了关闭Transaction closeTransaction(tx); // may have fetched a connection so lets call close() throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } } // 这个关闭很简单,就是异常了如果Transaction对象不为空,关闭,做垃圾清理 private void closeTransaction(Transaction tx) { if (tx != null) { try { tx.close(); } catch (SQLException ignore) { // Intentionally ignore. Prefer previous error. } } }

好了,我么来看下 SqlSession 的实现

public class DefaultSqlSession implements SqlSession {
// 获取配置
  private final Configuration configuration;
  // 这个是核心,后面的执行都是他来做的。
  private final Executor executor;

  private final boolean autoCommit;
  // 脏数据标记
  private boolean dirty;
  private List<Cursor<?>> cursorList;

  public DefaultSqlSession(Configuration configuration,
  Executor executor, boolean autoCommit) {
    this.configuration = configuration;
    this.executor = executor;
    this.dirty = false;
    this.autoCommit = autoCommit;
  }
  ......
}

题外话,有时候我们需要最一些特殊的操作,比如我们根据业务要求要进行大量数据的批量提交,并包含一定的逻辑,这时候我们想获得 Connection,怎么做呢?
这时候我们可以通过 DefaultSqlSession 的 getConnection 方法获取,但是需要注意的是,这个时候我们要控制好事务,这一点尤为重要。

  @Override
  public Connection getConnection() {
    try {
      return executor.getTransaction().getConnection();
    } catch (SQLException e) {
      throw ExceptionFactory.wrapException("Error getting a new connection.  Cause: " + e, e);
    }
  }

接下来,我们以其中一个方法为突破口,来分析一下,不失一般性,我们以 insert 为例

  @Override
  public int insert(String statement, Object parameter) {
    return update(statement, parameter);
  }


  @Override
  public int update(String statement, Object parameter) {
    try {
        // 脏数据标记
      dirty = true;
    //   在SqlSessionFactoty中,我们加载MapperLocation的mapper,
    // 通过parse方法,解析到Configuration对象中。
    // 这里再通过statement这个key从mappedStatements这个map中把它取出来
      MappedStatement ms = configuration.getMappedStatement(statement);
    // 通过DefaultSqlSession的executor执行相应的方法,这里的executor也是一个接口,
    // 在前面openSession中我们介绍了,它根据不同的执行类型创建对应的实现
      return executor.update(ms, wrapCollection(parameter));
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

总结:

总体来说,session 的构建还是很简单的,需要注意的是,采用面向接口编程,需要根据不同的参数实例化选择不同实现对象,比较绕。通过 SqlSession 获取 session,session 里包含执行代码需要的其他对象,这些对象根据实际需要构建,最后统一进入到 executor 中去执行。下一节,我们将分析一下 Executor