Mybatis 深入淺出 -- 執(zhí)行篇

Mybatis 執(zhí)行流程深入淺出

本文繼上篇mybatis初始化流程后,剖析其執(zhí)行流程

上篇文章傳送門

還是這幾個靈魂問題:

  1. Mybatis解決了什么問題? 無非是簡化數(shù)據(jù)庫操作、實現(xiàn)封裝、讓程序員更關注SQL本身、維護便利
  2. 它是如何解決這些問題的?
  3. Mybatis是運行在什么樣的環(huán)境下的?
  4. 它如何讀取解析用戶定義的配置信息?即如何初始化的
  5. 它的環(huán)境結構是什么樣的?
  6. 在這一環(huán)境下如何 實現(xiàn)做增刪查改
  7. 如何執(zhí)行SQL
  8. 如何執(zhí)行動態(tài)SQL
  9. 如何拼接查詢參數(shù)等等

上篇文章解答了 2問的 1、2、3小問,這篇文章就來說說剩下的幾個問題
也是大家使用得最多、最關心的問題


正經(jīng)的分割線


先給出一張圖,幫助大家能快速了解流程

Mybatis的執(zhí)行流程.png

同樣,這里搬出我們上篇文章的TestCase

注意 閱讀 序號 (1)、(2)、(3)、(4)、(5)、(6)...
Test.java

    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(“xxx/mybatis.xml”);
    // 使用一個SqlSession作為此次連接, 主要講這兒,初始化流程
    SqlSession sqlSession = sqlSessionFactory.openSession();
    (1)動態(tài)代理獲取代理的mapper對象
    CustomMapper mapper = sqlSession.getMapper(DemoMapper.class);
    Map<String,Object> map = new HashMap<>();
    map.put("id","1");
    (4) 執(zhí)行代理對象的方法
    System.out.println(mapper.select(map));
    sqlSession.close();

獲取動態(tài)代理的mapper

DefaultSqlSession

  (2)通過默認的sqlsession獲取到上篇文章講到的configuration(存儲著mappers)
  @Override
  public <T> T getMapper(Class<T> type) {
    // 從
    return configuration.getMapper(type, this);
  }

MapperRegistry

  (2)從knownMappers中拿到 代理工廠,使用工廠生成代理對象
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }

這里貼上關鍵點:本質是通過Proxy.newProxyInstance 來生成的代理對象
MapperRegistry

  (3)本質是通過MapperProxyFactory
public class MapperProxyFactory<T> {

  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<>();

  public MapperProxyFactory(Class<T> mapperInterface) {
    this.mapperInterface = mapperInterface;
  }

  public Class<T> getMapperInterface() {
    return mapperInterface;
  }

  public Map<Method, MapperMethod> getMethodCache() {
    return methodCache;
  }

  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

  public T newInstance(SqlSession sqlSession) {
    // 這里的 MapperProxy<T> implements InvocationHandler 借助了InvocationHandler,實現(xiàn)invoke 方法,進而實現(xiàn)代理對象調用邏輯控制
    具體調用請回到上面TestCase中的 (4)
    final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }

}

執(zhí)行代理對象的方法

MapperProxy

  (5)執(zhí)行具體方法
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) {
        //如果是object類的默認方法,比如equals,hashcode什么的
        return method.invoke(this, args);
      } else if (method.isDefault()) {
        //如果是default方法,java8,9處理不同。但都是把方法綁定到代理對象再調用
        if (privateLookupInMethod == null) {
          return invokeDefaultMethodJava8(proxy, method, args);
        } else {
          return invokeDefaultMethodJava9(proxy, method, args);
        }
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
    // 重點來了
    (6)獲取mapper執(zhí)行的方法
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    (8)真正執(zhí)行傳進來的mapper操作
    return mapperMethod.execute(sqlSession, args);
  }  
  
  (7)看是否有緩存,如果沒有就創(chuàng)建新的 mapper的執(zhí)行方法
  private MapperMethod cachedMapperMethod(Method method) {
    return methodCache.computeIfAbsent(method,
        k -> new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
  }

MapperMethod

public class MapperMethod {

  private final SqlCommand command;
  private final MethodSignature method;

  public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
    // SQL的信息,select|insert|xxx,初始化的MappedStatement等信息
    this.command = new SqlCommand(config, mapperInterface, method);
    // 當前執(zhí)行方法簽名,包含返回類型、resultHanlder、行范圍、查詢參數(shù)映射解析等信息
    this.method = new MethodSignature(config, mapperInterface, method);
  }

 (8)執(zhí)行sql
  public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    switch (command.getType()) {
      case INSERT: {
        // 如果是CUD操作,將傳入的參數(shù),映射到具體某個位置的SQL參數(shù)上
        // CUD操作其實都是調用的 update方法, 詳見(9)
        // 下面先講這個流程,select在之后講
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.insert(command.getName(), param));
        break;
      }
      case UPDATE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.update(command.getName(), param));
        break;
      }
      case DELETE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.delete(command.getName(), param));
        break;
      }
      case SELECT:
        if (method.returnsVoid() && method.hasResultHandler()) {
          executeWithResultHandler(sqlSession, args);
          result = null;
        } else if (method.returnsMany()) {
          result = executeForMany(sqlSession, args);
        } else if (method.returnsMap()) {
          result = executeForMap(sqlSession, args);
        } else if (method.returnsCursor()) {
          result = executeForCursor(sqlSession, args);
        } else {
          Object param = method.convertArgsToSqlCommandParam(args);
          result = sqlSession.selectOne(command.getName(), param);
          if (method.returnsOptional()
              && (result == null || !method.getReturnType().equals(result.getClass()))) {
            result = Optional.ofNullable(result);
          }
        }
        break;
      case FLUSH:
        result = sqlSession.flushStatements();
        break;
      default:
        throw new BindingException("Unknown execution method for: " + command.getName());
    }
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
      throw new BindingException("Mapper method '" + command.getName()
          + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
  }

  ······
}

增刪改 的流程

DefaultSqlSession

······
  @Override
  public int update(String statement, Object parameter) {
    try {
      (9)獲取MappedStatement,通過執(zhí)行器執(zhí)行
      dirty = true;
      MappedStatement ms = configuration.getMappedStatement(statement);
      return executor.update(ms, wrapCollection(parameter));
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }
······

SimpleExecutor

  @Override
  public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      // 創(chuàng)建一個statement的處理器
      (10)
      StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
      (11)
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.update(stmt);
    } finally {
      closeStatement(stmt);
    }
  }

  (11)這里就是jdbc熟悉的,獲取連接,準備Statement,設置參數(shù)到Statement
  private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    Connection connection = getConnection(statementLog);
    stmt = handler.prepare(connection, transaction.getTimeout());
    // parameterHandler設置參數(shù)
    handler.parameterize(stmt);
    return stmt;
  }

Configuration

(10)
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, 供插件用, 分頁插件可通過這兒來攔截執(zhí)行
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return statementHandler;
  }

DefaultParameterHandler

public class DefaultParameterHandler implements ParameterHandler {

  private final TypeHandlerRegistry typeHandlerRegistry;

  private final MappedStatement mappedStatement;
  private final Object parameterObject;
  private final BoundSql boundSql;
  private final Configuration configuration;

  public DefaultParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
    this.mappedStatement = mappedStatement;
    this.configuration = mappedStatement.getConfiguration();
    this.typeHandlerRegistry = mappedStatement.getConfiguration().getTypeHandlerRegistry();
    this.parameterObject = parameterObject;
    this.boundSql = boundSql;
  }

  @Override
  public Object getParameterObject() {
    return parameterObject;
  }

  (12)設置PreparedStatement 參數(shù)的邏輯
   @Override
   public void setParameters(PreparedStatement ps) {
    ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
    // 獲取到xml中配置的 參數(shù)
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    if (parameterMappings != null) {
      for (int i = 0; i < parameterMappings.size(); i++) {
        ParameterMapping parameterMapping = parameterMappings.get(i);
        if (parameterMapping.getMode() != ParameterMode.OUT) {
          Object value;
          // 拿到名稱
          String propertyName = parameterMapping.getProperty();
          // 首先看是否給參數(shù)設置了“額外”的名稱,如果是直接賦值
          if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
            value = boundSql.getAdditionalParameter(propertyName);
          } else if (parameterObject == null) {
            value = null;
            // 使用mybatis內(nèi)置的java常用類型的type映射
          } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
            value = parameterObject;
          } else {
            // 否則嘗試從元數(shù)據(jù)中嘗試獲取 值
            MetaObject metaObject = configuration.newMetaObject(parameterObject);
            value = metaObject.getValue(propertyName);
          }
          TypeHandler typeHandler = parameterMapping.getTypeHandler();
          JdbcType jdbcType = parameterMapping.getJdbcType();
          if (value == null && jdbcType == null) {
            // 都為空則,通過null獲取type
            jdbcType = configuration.getJdbcTypeForNull();
          }
          try {
            // 設置對應參數(shù) -- 底層PreparedStatement.setxxx(i + 1, value)
            typeHandler.setParameter(ps, i + 1, value, jdbcType);
          } catch (TypeException | SQLException e) {
            throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
          }
        }
      }
    }
  }

}

PreparedStatementHandler

  (13)給statement設置好參數(shù)后,到通過PreparedStatementHandler真正執(zhí)行update的時候了
  @Override
  public int update(Statement statement) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    // 獲取affectRows數(shù)量
    int rows = ps.getUpdateCount();
    Object parameterObject = boundSql.getParameterObject();
    // 主鍵返回后的執(zhí)行策略,比如處理數(shù)據(jù)庫自增主鍵
    KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
    keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
    return rows;
  }

到此增刪改操作流程全部結束

下面開始講Select執(zhí)行流程

和上述相同部分會一筆帶過,主要差異在結果集的映射上
這里 閱讀 序號重排 從mapper.select(map) 上的(4)開始,(5)、(6)...
MapperMethod

  (5)接著從MapperMethod開始
      case SELECT:
        if (method.returnsVoid() && method.hasResultHandler()) {
        // 如果無返回值,有結果集處理器
          executeWithResultHandler(sqlSession, args);
          result = null;
        } else if (method.returnsMany()) {
        // 如果返回list
          result = executeForMany(sqlSession, args);
        } else if (method.returnsMap()) {
        // 如果返回map
          result = executeForMap(sqlSession, args);
        } else if (method.returnsCursor()) {
        // 查詢下標
          result = executeForCursor(sqlSession, args);
        } else {
        // 如果單個結果
          Object param = method.convertArgsToSqlCommandParam(args);
          result = sqlSession.selectOne(command.getName(), param);
          if (method.returnsOptional()
              && (result == null || !method.getReturnType().equals(result.getClass()))) {
            result = Optional.ofNullable(result);
          }
        }
        break;
  
  private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
    List<E> result;
    (6)如果是多個則轉換成參數(shù)為map映射,單個則直接是當前參數(shù),沒有則為null
    Object param = method.convertArgsToSqlCommandParam(args);
    // 默認分頁,rowBounds 基于內(nèi)存實現(xiàn)分頁,不建議使用
    if (method.hasRowBounds()) {
      RowBounds rowBounds = method.extractRowBounds(args);
      result = sqlSession.selectList(command.getName(), param, rowBounds);
    } else {
      // 執(zhí)行查詢 詳見(9)
      result = sqlSession.selectList(command.getName(), param);
    }
    // issue #510 Collections & arrays support
    if (!method.getReturnType().isAssignableFrom(result.getClass())) {
      if (method.getReturnType().isArray()) {
        return convertToArray(result);
      } else {
        return convertToDeclaredCollection(sqlSession.getConfiguration(), result);
      }
    }
    return result;
  }
  
  (7)通過解析器解析參數(shù),構造參數(shù)映射
  public Object convertArgsToSqlCommandParam(Object[] args) {
    return paramNameResolver.getNamedParams(args);
  }

ParamNameResolver

  (8)解析names映射的地方,在mapper方法上添加了 @Param 注解,會解析到names里
  public ParamNameResolver(Configuration config, Method method) {
    final Class<?>[] paramTypes = method.getParameterTypes();
    final Annotation[][] paramAnnotations = method.getParameterAnnotations();
    final SortedMap<Integer, String> map = new TreeMap<>();
    int paramCount = paramAnnotations.length;
    // get names from @Param annotations
    for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {
      if (isSpecialParameter(paramTypes[paramIndex])) {
        // skip special parameters
        continue;
      }
      String name = null;
      for (Annotation annotation : paramAnnotations[paramIndex]) {
        if (annotation instanceof Param) {
          hasParamAnnotation = true;
          name = ((Param) annotation).value();
          break;
        }
      }
      if (name == null) {
        // @Param was not specified.
        //Spring MVC 底層調用的不是JDK的API  Spring MVC底層是去解析字節(jié)碼
        //在jdk8以前 調用這個getName 會有問題 arg0
        //jdk8
        if (config.isUseActualParamName()) {
          name = getActualParamName(method, paramIndex);
        }
        if (name == null) {
          // use the parameter index as the name ("0", "1", ...)
          // gcode issue #71
          name = String.valueOf(map.size());
        }
      }
      map.put(paramIndex, name);
    }
    names = Collections.unmodifiableSortedMap(map);
  }
  public Object getNamedParams(Object[] args) {
    final int paramCount = names.size();
    if (args == null || paramCount == 0) {
      return null;
    } else if (!hasParamAnnotation && paramCount == 1) {
      return args[names.firstKey()];
    } else {
      final Map<String, Object> param = new ParamMap<>();
      int i = 0;
      for (Map.Entry<Integer, String> entry : names.entrySet()) {
        //names : arg0,arg1
        param.put(entry.getValue(), args[entry.getKey()]);
        // add generic param names (param1, param2, ...)
        final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1);
        // ensure not to overwrite parameter named with @Param
        if (!names.containsValue(genericParamName)) {
          param.put(genericParamName, args[entry.getKey()]);
        }
        i++;
      }
      return param;
    }
  }

DefaultSqlSession

  (9)
  @Override
  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
      MappedStatement ms = configuration.getMappedStatement(statement);
      // 通過執(zhí)行器執(zhí)行查詢
      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();
    }
  }

BaseExecutor

  (10)
  @Override
  public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    BoundSql boundSql = ms.getBoundSql(parameter);
    (11)獲取緩存的key
    CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
    (12)
    return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
  }


  @Override
  public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
    if (closed) {
      throw new ExecutorException("Executor was closed.");
    }
    CacheKey cacheKey = new CacheKey();
    // 根據(jù)SQL的id(com.DemoMapper.select),開啟分頁的查詢范圍(起始位置,查詢條數(shù)),SQL語句,從方法上傳過來的參數(shù),返回的結果value值
    // 五個條件來判斷,是否是相同的查詢,做緩存key
    cacheKey.update(ms.getId());
    cacheKey.update(rowBounds.getOffset());
    cacheKey.update(rowBounds.getLimit());
    cacheKey.update(boundSql.getSql());
    // 獲取到xml中配置的 參數(shù)
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();
    // mimic DefaultParameterHandler logic
  // 這里與上面做CUD操作時的 (12)DefaultParameterHandler設置PreparedStatement參數(shù)的邏輯 相同,不再贅述
    for (ParameterMapping parameterMapping : parameterMappings) {
      if (parameterMapping.getMode() != ParameterMode.OUT) {
        Object value;
        String propertyName = parameterMapping.getProperty();
        if (boundSql.hasAdditionalParameter(propertyName)) {
          value = boundSql.getAdditionalParameter(propertyName);
        } else if (parameterObject == null) {
          value = null;
        } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
          value = parameterObject;
        } else {
          MetaObject metaObject = configuration.newMetaObject(parameterObject);
          value = metaObject.getValue(propertyName);
        }
        // 通過獲取到的value更新 緩存key
        cacheKey.update(value);
      }
    }
    if (configuration.getEnvironment() != null) {
      // issue #176
      cacheKey.update(configuration.getEnvironment().getId());
    }
    return cacheKey;
  }

  // CacheKey類 中代碼計算hashcode
  public void update(Object object) {
    // 如果為空則為1,不為空判斷是否是數(shù)組,不是直接返回對象hashcode,是則判斷具體是哪一種類型數(shù)組,進行hash運算
    int baseHashCode = object == null ? 1 : ArrayUtil.hashCode(object);
    //每update一次累加一次
    count++;
    checksum += baseHashCode;
    baseHashCode *= count;
    hashcode = multiplier * hashcode + baseHashCode;
    updateList.add(object);
  }

  (12)執(zhí)行查詢
  @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.");
    }
    // 如果當前沒有經(jīng)歷過查詢,并且需要更新緩存
    if (queryStack == 0 && ms.isFlushCacheRequired()) {
      clearLocalCache();
    }
    List<E> list;
    try {
      queryStack++;
      list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
      if (list != null) {
        //對于數(shù)據(jù)庫的存儲過程進行輸出資源處理
        handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
      } else {
        (13)查詢
        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 <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 {
      (13)
      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;
  }

SimpleExecutor

  (13)和上面CUD 相同的邏輯
  @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());
      (14)
      return handler.query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }

PreparedStatementHandler

  (14)
  @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    (15)處理結果集
    return resultSetHandler.handleResultSets(ps);
  }

DefaultResultSetHandler

  (15)
  @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;
    // 有多個結果集取第一個,將ps取得的結果集 - ResultSet 包裝在 wrapper中,其中還包含configuration信息
    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);
      (16)處理單個結果集
      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);
  }

  (16)
  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 {
        if (resultHandler == null) {
          DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
          handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
          multipleResults.add(defaultResultHandler.getResultList());
        } else {
          (17)處理具體一行的結果值
          handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
        }
      }
    } finally {
      // issue #228 (close resultsets)
      closeResultSet(rsw.getResultSet());
    }
  }  

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

  (18)
  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);
    // 遍歷resultSet
    while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
      // 解析鑒別器,<discriminator>標簽 - 用于 當某個字段滿足一定條件時,使用指定的resultMap。比如
      //     <discriminator column="enabled" javaType="int">
      //        <case value="1" resultMap="testMap1"/>
      //        <case value="0" resultMap="testMap2"/>
      //    </discriminator>
      ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
      (19)取值
      Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
      // 將取出來的值,放入context中,再將context的值存入resultHandler
      storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
    }
  }

  (19)
  private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
    // 當需要進行循環(huán)結果集映射時,使用到的懶加載 LoadPair
    final ResultLoaderMap lazyLoader = new ResultLoaderMap();
    // 創(chuàng)建空map存儲值
    Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
    // 有結果集的處理器
    if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
      // 借助于初始化生成MetaObject信息 利用反射信息,操作返回值
      final MetaObject metaObject = configuration.newMetaObject(rowValue);
      boolean foundValues = this.useConstructorMappings;
      // 是否自動映射 通過resultMap 的 automapping屬性設置, 默認啟用
      if (shouldApplyAutomaticMappings(resultMap, false)) {
        foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
      }
      // 自定義的映射 比如 通過resultMap 的 子標簽<id>、<result>設置
      foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
      foundValues = lazyLoader.size() > 0 || foundValues;
      rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
    }
    return rowValue;
  }

  // 到這里查詢就結束了,后面就是上面的流程,關閉ps等資源,然后將結果放入緩存等。

看到這兒的都是狼人,現(xiàn)在來看看圖,自我總結一下

Mybatis的執(zhí)行流程.png

下篇文章將會剖析 可能是大家開發(fā)中用到最多的開源插件源碼 PageHelper

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容