mybatis源码(四)SqlSession执行mapper的过程下篇


mybatis源码(四)SqlSession执行mapper的过程下篇

代码案例:以SqlSession的selectList为例



    


public class TestUserMapper {
    private static SqlSessionFactory sqlSessionFactory;
    @BeforeClass
    public static void init(){
        try {
            Reader reader = Resources.getResourceAsReader("mybatis.config.xml");
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Test
    public void TestMybatis(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        List userList = sqlSession.selectList("selectUsers");
        System.out.println(userList.size());
        System.out.println(userList.get(0).getNickname());
        System.out.println(userList.get(0).getCreateTime());
    }
}

首先SqlSession是一个接口,有一个DefaultSqlSession的实现类,实现类实现该接口的代码如下:

  @Override
  public  List selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
      // 根据Mapper的Id,获取对应的MappedStatement对象
      MappedStatement ms = configuration.getMappedStatement(statement);
      // 以MappedStatement对象作为参数,调用Executor的query()方法
      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();
    }
  }

configuration的mapperstatement的对象的值 是在SqlSession创建的时候,通过XmlConfigBuilder解析mybatis-config主配置文件的时候,添加进去的 configration中有一个map集合如下图所示

protected final Map mappedStatements = new StrictMap("Mapped Statements collection");
该属性是一个Map对象,它的key为mapperSql配置的id。如果sql是通过xml注释的。则id为命名空间加上 ,如果sql通过java注解配置。则id为mapper接口的全限定名称加上方法名称

通过上述源码可以看到,实际操作数据库的事Excutor执行器,这里用到了一个外观模式,为了对用户提供友好的访问接口,Excutor执行器是一个接口,有几个实现类

进入实现类BaseExecutor中,查看query的源码

queryFromDatabase 这个地方由于缓存中没有我们要找的数据,所以从数据库中进行数据的读取,这个doQuery方法用到了模板方法设计模式根据上述的类图,可以看到有几个实现类,分别提供了不同的实现
 @Override
    public  List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
        // 获取BoundSql对象,BoundSql是对动态SQL解析生成的SQL语句和参数映射信息的封装
        BoundSql boundSql = ms.getBoundSql(parameter);
        // 创建CacheKey,用于缓存Key
        CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
        // 调用重载的query()方法
        return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
    }

    @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;
            if (list != null) {
                handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
            } else {
                // 缓存中获取不到,则调用queryFromDatabase()方法从数据库中查询
                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;
 实现类1:simpleExecutor 的实现方式
@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对象
    StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
    // 调用prepareStatement()方法,创建Statement对象,并进行设置参数等操作
    stmt = prepareStatement(handler, ms.getStatementLog());
    // 调用StatementHandler对象的query()方法执行查询操作
    return handler.query(stmt, resultHandler);
  } finally {
    closeStatement(stmt);
  }
}

 statementhandler的创建,默认是PREPARED 类型的

StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));

实现类2:BatchExecutor

@Override
public  List doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
    throws SQLException {
  Statement stmt = null;
  try {
    flushStatements();
    Configuration configuration = ms.getConfiguration();
    StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameterObject, rowBounds, resultHandler, boundSql);
    Connection connection = getConnection(ms.getStatementLog());
    stmt = handler.prepare(connection, transaction.getTimeout());
    handler.parameterize(stmt);
    return handler.query(stmt, resultHandler);
  } finally {
    closeStatement(stmt);
  }
}

实现类3:ReuseExecutor

@Override
public  List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
  Configuration configuration = ms.getConfiguration();
  StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
  Statement stmt = prepareStatement(handler, ms.getStatementLog());
  return handler.query(stmt, resultHandler);
}
Statement 操作数据库就是JDBC提供的操作数据的实现

从三述三种实现类中可以看出StatementHandler是操作Statement的。

StatementHandler也是一个接口,通过具体的实现类,来操作数据。StatementHandler的实现类有SimpleStatementHandler、PreparedStatementHandler、CallableStatementHandler   实现类1:SimpleStatementHandler中的代码实现
  @Override
  public  List query(Statement statement, ResultHandler resultHandler) throws SQLException {
    String sql = boundSql.getSql();
    statement.execute(sql);
    return resultSetHandler.handleResultSets(statement);
  }

实现类2:PreparedStatementHandler

  @Override
  public  List query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    // 调用PreparedStatement对象的execute()方法,执行SQL语句
    ps.execute();
    // 调用ResultSetHandler的handleResultSets()方法处理结果集
    return resultSetHandler. handleResultSets(ps);
  }

实现类3:CallableStatementHandler

  @Override
  public  List query(Statement statement, ResultHandler resultHandler) throws SQLException {
    CallableStatement cs = (CallableStatement) statement;
    cs.execute();
    List resultList = resultSetHandler.handleResultSets(cs);
    resultSetHandler.handleOutputParameters(cs);
    return resultList;
  }
通过上述三个statementHandler可以看出,对结果集的处理,是通过ResultSetHandler进行处理的。即:return resultSetHandler.handleResultSets(statement);
ResultSetHandler 是一个接口实现,只有一个实现类
public interface ResultSetHandler {

   List handleResultSets(Statement stmt) throws SQLException;

   Cursor handleCursorResultSets(Statement stmt) throws SQLException;

  void handleOutputParameters(CallableStatement cs) throws SQLException;

}

DefaultResultSetHandler

 //
  // 处理结果集
  //
  @Override
  public List handleResultSets(Statement stmt) throws SQLException {
    ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
    final List multipleResults = new ArrayList();
    int resultSetCount = 0;
    // 1、获取ResultSet对象,將ResultSet对象包装为ResultSetWrapper
    ResultSetWrapper rsw = getFirstResultSet(stmt);
    // 2、获取ResultMap信息,一般只有一个ResultMap
    List resultMaps = mappedStatement.getResultMaps();
    int resultMapCount = resultMaps.size();
    // 校验ResultMap,如果该ResultMap名称没有配置,则抛出异常
    validateResultMapsCount(rsw, resultMapCount);
    // 如果指定了多个ResultMap,则对每个ResultMap进行处理
    while (rsw != null && resultMapCount > resultSetCount) {
      ResultMap resultMap = resultMaps.get(resultSetCount);
      // 3、调用handleResultSet方法处理结果集
      handleResultSet(rsw, resultMap, multipleResults, null);
      // 获取下一个结果集对象,需要JDBC驱动支持多结果集
      rsw = getNextResultSet(stmt);
      cleanUpAfterHandlingResultSet();
      resultSetCount++;
    }
    // 如果JDBC驱动支持多结果集,可以通过标签resultSets属性,该属性一般情况不会指定
    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方法处理结果集
          handleResultSet(rsw, resultMap, null, parentMapping);
        }
        rsw = getNextResultSet(stmt);
        cleanUpAfterHandlingResultSet();
        resultSetCount++;
      }
    }
    // 对multipleResults进行处理,如果只有一个结果集,则返回结果集中的元素,否则返回多个结果集
    return collapseSingleResultList(multipleResults);
  }
  @SuppressWarnings("unchecked")
  private List collapseSingleResultList(List multipleResults) {
    return multipleResults.size() == 1 ? (List) multipleResults.get(0) : multipleResults;
  }



至此,就完成了SqlSession.selectList的 流程,源码涉及的东西比较多,这就是个大致的流程  

 

session.selectList("XXX"); 执行流程
1.调用SqlSession接口的selectList()方法
2.默认执行的是DefaultSqlSession的 List selectList(String statement)方法
2.1.根据Mapper的Id,从configuration对象中获取对应的MappedStatement对象
  2.2 通过Executor执行器,执行query方法( List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;)
  2.3 有2个实现类,选择一个进去BaseExecutor.query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException
    2.3.1 获取BoundSql对象,BoundSql是对动态SQL解析生成的SQL语句和参数映射信息的封装
    2.3.2 创建CacheKey,用于缓存Key
    2.3.3 根据缓存key从缓存中localCache(PerpetualCache是mybatis的以及缓存对象)获取结果
    2.3.4 如果结果不为空,从缓存中取数据
    2.3.5 如果数据为空,从数据库中查询数据 private List queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
      2.3.5.1 调用子类进行查询(代码中了用了模板方法) public List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
      2.3.5.2 获取StatementHandler对象
      2.3.5.3 调用prepareStatement()方法,创建Statement对象,并进行设置参数等操作
        2.3.5.3.1 获取JDBC中的Connection对象
        2.3.5.3.2 调用StatementHandler的prepare()方法创建Statement对象 stmt = handler.prepare(connection, transaction.getTimeout());
        2.3.5.3.3 调用StatementHandler对象的parameterize()方法设置参数
            2.3.5.3.3.1 PreparedStatementHandler.parameterize(Statement statement) throws SQLException 进行赋值操作
            2.3.5.3.3.2 调用ParameterHandler的实现类DefaultParameterHandler进行赋值操作。 // 获取所有参数映射信息List parameterMappings = boundSql.getParameterMappings();
      2.3.5.4 调用StatementHandler对象的query()方法执行查询操作
      2.3.5.6 调用StatementHandler有多个子类,选择一个,这里选择PreparedStatementHandler。调用其中女的query方法
      2.3.5.7 用PreparedStatement对象的execute()方法,执行SQL语句
      2.3.5.8 调用ResultSetHandler的handleResultSets()方法处理结果集.ResultSetHandler是一个接口,有一个默认的实现类来完成该功能
          实现类为DefaultResultSetHandler
    2.3.6 数据库中查询出的结果放入到缓存中