Loading

33-MyBatis-3(源码流程)

HelloWorld 源码全流程

1. SqlSessionFactory 的初始化

1.1 SqlSessionFactoryBuilder

public SqlSessionFactory build(InputStream inputStream
        , String environment, Properties properties) {
    try {
      // 创建解析器
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      // ===== ↓↓↓ Step Into ↓↓↓ =====
      // 使用 XPATH 解析 XML 配置文件,将配置文件封装为 Configuration 对象
      // 返回 DefaultSqlSessionFactory 对象,该对象拥有 Configuration 对象(封装配置文件信息)
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        inputStream.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
}

public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
}

创建 XMLConfigBuilder 对象,这个类是 BaseBuilder 的子类,BaseBuilder 类图如下:

看到这些子类基本上都是以 Builder 结尾,这里使用的是建造者设计模式。

1.2 XMLConfigBuilder

public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
    // XPathParser 基于 Java XPath 解析器,用于解析 MyBatis 中的配置文件
    this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}

public Configuration parse() {
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
    // ===== ↓↓↓ Step Into ↓↓↓ =====
    parseConfiguration(parser.evalNode("/configuration")); // 根节点
    return configuration;
}

private void parseConfiguration(XNode root) {
    // 挨个解析<configuration>下的每一个子节点,将详细信息保存在 configuration 中
    try {
      Properties settings = settingsAsPropertiess(root.evalNode("settings"));
      //issue #117 read properties first
      propertiesElement(root.evalNode("properties"));
      loadCustomVfs(settings);
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      // ===== ↓↓↓ Step Into ↓↓↓ =====
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      // ===== ↓↓↓ Step Into ↓↓↓ =====
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
}

// props ←→ <settings>
private void settingsElement(Properties props) throws Exception {
    configuration.setAutoMappingBehavior(AutoMappingBehavior
            .valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
    configuration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior
            .valueOf(props.getProperty("autoMappingUnknownColumnBehavior", "NONE")));
    configuration.setCacheEnabled(
            booleanValueOf(props.getProperty("cacheEnabled"), true));
    configuration.setProxyFactory(
            (ProxyFactory) createInstance(props.getProperty("proxyFactory")));
    configuration.setLazyLoadingEnabled(booleanValueOf(
            props.getProperty("lazyLoadingEnabled"), false));
    configuration.setAggressiveLazyLoading(
            booleanValueOf(props.getProperty("aggressiveLazyLoading"), true));
    configuration.setMultipleResultSetsEnabled(
            booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true));
    configuration.setUseColumnLabel(
            booleanValueOf(props.getProperty("useColumnLabel"), true));
    configuration.setUseGeneratedKeys(
            booleanValueOf(props.getProperty("useGeneratedKeys"), false));
    configuration.setDefaultExecutorType(
            ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
    configuration.setDefaultStatementTimeout(
            integerValueOf(props.getProperty("defaultStatementTimeout"), null));
    configuration.setDefaultFetchSize(
            integerValueOf(props.getProperty("defaultFetchSize"), null));
    configuration.setMapUnderscoreToCamelCase(
            booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));
    configuration.setSafeRowBoundsEnabled(
            booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));
    configuration.setLocalCacheScope(
            LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));
    configuration.setJdbcTypeForNull(
            JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));
    configuration.setLazyLoadTriggerMethods(stringSetValueOf(
            props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));
    configuration.setSafeResultHandlerEnabled(
            booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true));
    configuration.setDefaultScriptingLanguage(
            resolveClass(props.getProperty("defaultScriptingLanguage")));
    configuration.setCallSettersOnNulls(
            booleanValueOf(props.getProperty("callSettersOnNulls"), false));
    configuration.setUseActualParamName(
            booleanValueOf(props.getProperty("useActualParamName"), false));
    configuration.setLogPrefix(props.getProperty("logPrefix"));
    @SuppressWarnings("unchecked")
    Class<? extends Log> logImpl =
            (Class<? extends Log>)resolveClass(props.getProperty("logImpl"));
    configuration.setLogImpl(logImpl);
    configuration.setConfigurationFactory(
            resolveClass(props.getProperty("configurationFactory")));
}

private void mapperElement(XNode parent) throws Exception {
    if (parent != null) {
      for (XNode child : parent.getChildren()) {
        if ("package".equals(child.getName())) {
          String mapperPackage = child.getStringAttribute("name");
          configuration.addMappers(mapperPackage);
        } else {
          String resource = child.getStringAttribute("resource");
          String url = child.getStringAttribute("url");
          String mapperClass = child.getStringAttribute("class");
          if (resource != null && url == null && mapperClass == null) {
            ErrorContext.instance().resource(resource);
            InputStream inputStream = Resources.getResourceAsStream(resource);
            XMLMapperBuilder mapperParser = new XMLMapperBuilder(
                    inputStream, configuration, resource, configuration.getSqlFragments());
            // ===== ↓↓↓ Step Into ↓↓↓ =====> #1.3
            mapperParser.parse();
          } else if (resource == null && url != null && mapperClass == null) {
            ErrorContext.instance().resource(url);
            InputStream inputStream = Resources.getUrlAsStream(url);
            XMLMapperBuilder mapperParser = new XMLMapperBuilder(
                    inputStream, configuration, url, configuration.getSqlFragments());
            mapperParser.parse();
          } else if (resource == null && url == null && mapperClass != null) {
            Class<?> mapperInterface = Resources.classForName(mapperClass);
            configuration.addMapper(mapperInterface);
          } else {
            throw new BuilderException("A mapper element may only specify a url"
                    + ", resource or class, but not more than one.");
          }
        }
      }
    }
}

1.3 XMLMapperBuilder

private void configurationElement(XNode context) {
    try {
      String namespace = context.getStringAttribute("namespace");
      if (namespace == null || namespace.equals("")) {
        throw new BuilderException("Mapper's namespace cannot be empty");
      }
      builderAssistant.setCurrentNamespace(namespace);
      cacheRefElement(context.evalNode("cache-ref"));
      cacheElement(context.evalNode("cache"));
      parameterMapElement(context.evalNodes("/mapper/parameterMap"));
      resultMapElements(context.evalNodes("/mapper/resultMap"));
      // 可重用 SQL
      sqlElement(context.evalNodes("/mapper/sql"));
      // ===== ↓↓↓ Step Into ↓↓↓ =====
      buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing Mapper XML. Cause: " + e, e);
    }
}

private void buildStatementFromContext(List<XNode> list) {
    if (configuration.getDatabaseId() != null) {
      buildStatementFromContext(list, configuration.getDatabaseId());
    }
    // ===== ↓↓↓ Step Into ↓↓↓ =====
    buildStatementFromContext(list, null);
}

private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
    for (XNode context : list) {
      // 解析 CRUD 标签的解析器
      final XMLStatementBuilder statementParser = new XMLStatementBuilder(
              configuration, builderAssistant, context, requiredDatabaseId);
      try {
        // ===== ↓↓↓ Step Into ↓↓↓ =====> #1.4
        statementParser.parseStatementNode();
      } catch (IncompleteElementException e) {
        configuration.addIncompleteStatement(statementParser);
      }
    }
}

1.4 XMLStatementBuilder

public void parseStatementNode() {

    // 将 CRUD 标签中的一个个属性都解析出来 ...

    // ===== ↓↓↓ Step Into ↓↓↓ =====
    builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType
        , fetchSize, timeout, parameterMap, parameterTypeClass, resultMap
        , resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered
        , keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}

1.5 MapperBuilderAssistant

public MappedStatement addMappedStatement(对应上一步的那一堆配置...) {
    MappedStatement.Builder statementBuilder = new MappedStatement.Builder(
            configuration, id, sqlSource, sqlCommandType).配置全部加进来;

    ParameterMap statementParameterMap =
            getStatementParameterMap(parameterMap, parameterType, id);
    if (statementParameterMap != null) {
      statementBuilder.parameterMap(statementParameterMap);
    }

    // 根据解析出来的配置,构建一个 MappedStatement 对象(封装一个 CRUD 标签的详细信息)
    MappedStatement statement = statementBuilder.build();
    // 把这个 MappedStatement 加入到 configuration 中
    configuration.addMappedStatement(statement);
    return statement;
}

1.6 Configuration

Configuration 对象保存了所有配置文件(全局、映射) 的详细信息。

2. 获取 SqlSession

Mybatis 四大组件之一的 Executor 在这一步会被创建。

2.1 DefaultSqlSessionFactory

@Override
public SqlSession openSession(boolean autoCommit) {
    // ===== ↓↓↓ Step Into ↓↓↓ =====
    return openSessionFromDataSource(
            configuration.getDefaultExecutorType(), null, autoCommit);
}

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);
      // ===== ↓↓↓ Step Into ↓↓↓ =====> 得先创建 Executor → #2.2
      final Executor executor = configuration.newExecutor(tx, execType);
      // Executor 作为 SqlSession 构造器形参之一,只有先有它才能创建 SqlSession → #2.5
      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();
    }
}

2.2 Configuration

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    // 根据 Executor 在全局配置文件中配置的类型,创建出相应的 XxxExecutor
    if (ExecutorType.BATCH == executorType) {
      executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
      executor = new ReuseExecutor(this, transaction);
    } else { // SIMPLE
      executor = new SimpleExecutor(this, transaction); // √
    }
    if (cacheEnabled) {
      // ===== ↓↓↓ Step Into ↓↓↓ =====> 若配置了二级缓存 → #2.3
      executor = new CachingExecutor(executor); // 包装 Executor
    }
    // ===== ↓↓↓ Step Into ↓↓↓ =====> 返回经拦截器们包装后的 Executor → #2.4
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
}

2.3 CachingExecutor

public class CachingExecutor implements Executor {

  // 原始 Executor
  private Executor delegate;
  // 二级缓存
  private TransactionalCacheManager tcm = new TransactionalCacheManager();

  // 对传进来的 Executor 做了包装,并返回包装后的 Executor
  public CachingExecutor(Executor delegate) {
    this.delegate = delegate;
    delegate.setExecutorWrapper(this);
  }

  // ...
}

2.4 InterceptorChain

private final List<Interceptor> interceptors = new ArrayList<Interceptor>();

public Object pluginAll(Object target) {
    // 每个拦截器都来重新包装 Executor
    for (Interceptor interceptor : interceptors) {
      target = interceptor.plugin(target);
    }
    return target;
}

2.5 DefaultSqlSession

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

3. 返回 Mapper 代理对象

3.1 DefaultSqlSession

@Override
public <T> T getMapper(Class<T> type) {
    // ===== ↓↓↓ Step Into ↓↓↓ =====
    return configuration.<T>getMapper(type, this);
}

3.2 Configuration

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    // ===== ↓↓↓ Step Into ↓↓↓ =====
    return mapperRegistry.getMapper(type, sqlSession);
}

3.3 MapperRegistry

@SuppressWarnings("unchecked")
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    // 根据 Mapper<I> 类型从这个 Map 中拿到对应的 MapperProxyFactory
    final MapperProxyFactory<T> mapperProxyFactory
            = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      // ===== ↓↓↓ Step Into ↓↓↓ =====> mapperProxyFactory 根据 sqlSession 创建 MapperProxy
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
}

3.4 MapperProxyFactory

public T newInstance(SqlSession sqlSession) {
    // ===== ↓↓↓ Step Into ↓↓↓ =====> #3.5 → 创建 MapperProxy 对象
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(
                                sqlSession, mapperInterface, methodCache);
    // ===== ↓↓↓ Step Into ↓↓↓ =====> 对上一步创建的 MapperProxy 对象做动态代理,并返回
    return newInstance(mapperProxy);
}

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

3.5 MapperProxy

public class MapperProxy<T> implements InvocationHandler, Serializable {

  private static final long serialVersionUID = -6424540398559729838L;
  private final SqlSession sqlSession;
  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache;

  public MapperProxy(SqlSession sqlSession
          , Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
    this.sqlSession = sqlSession;
    this.mapperInterface = mapperInterface;
    this.methodCache = methodCache;
  }

}

4. 调用查询方法

4.1 MapperProxy

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if (Object.class.equals(method.getDeclaringClass())) {
      try {
        return method.invoke(this, args);
      } catch (Throwable t) {
        throw ExceptionUtil.unwrapThrowable(t);
      }
    }
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    // ===== ↓↓↓ Step Into ↓↓↓ =====> 传入 sqlSession 和方法参数
    return mapperMethod.execute(sqlSession, args);
}

4.2 MapperMethod

public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    switch (command.getType()) {
      case INSERT: {
    	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 {
          // ===== ↓↓↓ Step Into ↓↓↓ =====> 封装参数 → 下面的方法
          Object param = method.convertArgsToSqlCommandParam(args);
          // ===== ↓↓↓ Step Into ↓↓↓ =====> #4.4
          result = sqlSession.selectOne(command.getName(), param);
        }
        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;
}

public static class MethodSignature {
    private final ParamNameResolver paramNameResolver;

    public Object convertArgsToSqlCommandParam(Object[] args) {
      // ===== ↓↓↓ Step Into ↓↓↓ =====> 调用参数解析器 → #4.3
      return paramNameResolver.getNamedParams(args);
    }
}

4.3 ParamNameResolver

private static final String GENERIC_NAME_PREFIX = "param";

public ParamNameResolver(Configuration config, Method method) {
    final Class<?>[] paramTypes = method.getParameterTypes();
    final Annotation[][] paramAnnotations = method.getParameterAnnotations();
    final SortedMap<Integer, String> map = new TreeMap<Integer, String>();
    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.
        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<Object>();
      int i = 0;
      for (Map.Entry<Integer, String> entry : names.entrySet()) {
        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;
    }
}

4.4 DefaultSqlSession

@Override
public <T> T selectOne(String statement, Object parameter) {
    // Popular vote was to return null on 0 results and throw exception on too many.
    // ===== ↓↓↓ Step Into ↓↓↓ =====
    List<T> list = this.<T>selectList(statement, parameter);
    if (list.size() == 1) {
      return list.get(0);
    } else if (list.size() > 1) {
      throw new TooManyResultsException("Expected one result (or null) to be"
              + "returned by selectOne(), but found: " + list.size());
    } else {
      return null;
    }
}

@Override
public <E> List<E> selectList(String statement, Object parameter) {
    // ===== ↓↓↓ Step Into ↓↓↓ =====
    // statement: cn.edu.nuist.mapper.TeacherMapper.getTeacherByTid
    return this.selectList(statement, parameter, RowBounds.DEFAULT);
}

@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
      // Configuration 成员:Map<String, MappedStatement> mappedStatements
      // 根据该 statement(select标签的唯一标识),拿到了对应的 MappedStatement
      // 该 MappedStatement 对象中封装了对应的 <select> 的详细信息
      MappedStatement ms = configuration.getMappedStatement(statement);
      // ===== ↓↓↓ Step Into ↓↓↓ =====> 先钻入下面的方法 → 然后是 #4.5
      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();
    }
}

// 嘿!
private Object wrapCollection(final Object object) {
    if (object instanceof Collection) {
      StrictMap<Object> map = new StrictMap<Object>();
      map.put("collection", object);
      if (object instanceof List) {
        map.put("list", object);
      }
      return map;
    } else if (object != null && object.getClass().isArray()) {
      StrictMap<Object> map = new StrictMap<Object>();
      map.put("array", object);
      return map;
    }
    return object;
}

  • BaseExecutor:基础执行器,封装了子类的公共方法,包括一级缓存、延迟加载、回滚、关闭等功能;
  • SimpleExecutor:简单执行器,每执行一条 sql 都会打开一个 Statement,执行完成后关闭;
  • ReuseExecutor:重用执行器,相较于 SimpleExecutor 多了 Statement 的缓存功能,其内部维护一个 Map<String, Statement>,每次编译完成的 Statement 都会进行缓存,不会关闭;
  • BatchExecutor:批量执行器,基于 JDBC 的 addBatch、executeBatch 功能,并且在当前 sql 和上一条 sql 完全一样的时候,重用 Statement,在调用 doFlushStatements 的时候,将数据刷新到数据库;
  • CachingExecutor:缓存执行器,装饰器模式,在开启缓存的时候。会在上面三种执行器的外面再包上 CachingExecutor;

4.5 CachingExecutor

@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);
    // ===== ↓↓↓ Step Into ↓↓↓ =====
    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")
        // 先看二级缓存(TransactionalCacheManager) 中有没有
        List<E> list = (List<E>) tcm.getObject(cache, key);
        if (list == null) {
          // ===== ↓↓↓ Step Into ↓↓↓ =====> #4.6
          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);
}

CachingExecutor 是对 Executor 的包装,所以最终还是调用原始 Executor 的 query 方法。

4.6 BaseExecutor

@SuppressWarnings("unchecked")
@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++;
      // 拿 cacheKey 在一级缓存(localCache) 中查找!
      list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
      if (list != null) {
        handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
      } else { // 没找到就去 DB 中找
        // ===== ↓↓↓ Step Into ↓↓↓ =====
        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 {
      // ===== ↓↓↓ Step Into ↓↓↓ =====> 4.7
      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;
}

4.7 SimpleExecutor*

在此方法内创建了 StatementHandler (ParameterHandler、ResultSetHandler)

@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();
      // ===== ↓↓↓ Step Into ↓↓↓ =====> StatementHandler(可用来创建 Statement 对象) → #4.8
      StatementHandler handler = configuration.newStatementHandler(
              wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      // ===== ↓↓↓ Step Into ↓↓↓ =====> 创建 Statement 对象 → 就在下面 ~
      stmt = prepareStatement(handler, ms.getStatementLog());
      // ===== ↓↓↓ Step Into ↓↓↓ =====> #4.9[3]
      return handler.<E>query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
}

private Statement prepareStatement(
        StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    // 获取连接
    Connection connection = getConnection(statementLog);
    // 创建 Statement(PreparedStatement、Statement、CallableStatement)
    stmt = handler.prepare(connection, transaction.getTimeout());
    // ===== ↓↓↓ Step Into ↓↓↓ =====> #4.11
    // SQL 参数设置。面上是 StatementHandler 调用的,实际是 ParameterHandler 来做的参数预编译
    // ParameterHandler 创建时机:创建 StatementHandler 时一并创建的 → #4.10
    handler.parameterize(stmt);
    return stmt;
}

4.8 Configuration

public StatementHandler newStatementHandler(Executor executor
        , MappedStatement mappedStatement, Object parameterObject
        , RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    // ===== ↓↓↓ Step Into ↓↓↓ =====> #4.9
    StatementHandler statementHandler = new RoutingStatementHandler(executor
            , mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
    // 使用拦截器包装 StatementHandler
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return statementHandler;
}

public ParameterHandler newParameterHandler(
        MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
    ParameterHandler parameterHandler = mappedStatement.getLang()
            .createParameterHandler(mappedStatement, parameterObject, boundSql);
    parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
    return parameterHandler;
}

public ResultSetHandler newResultSetHandler(Executor executor
        , MappedStatement mappedStatement, RowBounds rowBounds
        , ParameterHandler parameterHandler, ResultHandler
        resultHandler, BoundSql boundSql) {
    ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor,
            mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
    resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
    return resultSetHandler;
}

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

4.9 RoutingStatementHandler

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:
        // ===== ↓↓↓ Step Into ↓↓↓ =====> { super(...); } → #4.10
        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());
    }
}

@Override
public void parameterize(Statement statement) throws SQLException {
    delegate.parameterize(statement);
}

@Override
public <E> List<E> query(Statement statement
        , ResultHandler resultHandler) throws SQLException {
    // ===== ↓↓↓ Step Into ↓↓↓ =====> #4.11[2]
    return delegate.<E>query(statement, resultHandler);
}

  • BaseStatementHandler:基础语句处理器(抽象类),它基本把语句处理器接口的核心部分都实现了,包括配置绑定、执行器绑定、映射器绑定、参数处理器构建、结果集处理器构建、语句超时设置、语句关闭等,并另外定义了新的方法 instantiateStatement 供不同子类实现以便获取不同类型的语句连接,子类可以普通执行 SQL 语句,也可以做预编译执行,还可以执行存储过程等。
  • SimpleStatementHandler:普通语句处理器,继承 BaseStatementHandler 抽象类,对应 java.sql.Statement 对象的处理,处理普通的不带动态参数运行的 SQL,即执行简单拼接的字符串语句,同时由于 Statement 的特性,SimpleStatementHandler 每次执行都需要编译 SQL (注意:我们知道 SQL 的执行是需要编译和解析的)。
  • PreparedStatementHandler:预编译语句处理器,继承 BaseStatementHandler 抽象类,对应 java.sql.PrepareStatement 对象的处理,相比上面的普通语句处理器,它支持可变参数 SQL 执行,由于 PrepareStatement 的特性,它会进行预编译,在缓存中一旦发现有预编译的命令,会直接解析执行,所以减少了再次编译环节,能够有效提高系统性能,并预防 SQL 注入攻击(所以是系统默认也是我们推荐的语句处理器)。
  • CallableStatementHandler:存储过程处理器,继承 BaseStatementHandler 抽象类,对应 java.sql.CallableStatement 对象的处理,很明了,它是用来调用存储过程的,增加了存储过程的函数调用以及输出/输入参数的处理支持。
  • RoutingStatementHandler:路由语句处理器,直接实现了 StatementHandler 接口,作用如其名称,确确实实只是起到了路由功能,并把上面介绍到的三个语句处理器实例作为自身的委托对象而已,所以执行器在构建语句处理器时,都是直接 new 了 RoutingStatementHandler 实例。

4.10 BaseStatementHandler

protected BaseStatementHandler(Executor executor, MappedStatement
        mappedStatement, Object parameterObject, RowBounds rowBounds,
        ResultHandler resultHandler, BoundSql boundSql) {
    this.configuration = mappedStatement.getConfiguration();
    this.executor = executor;
    this.mappedStatement = mappedStatement;
    this.rowBounds = rowBounds;

    this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
    this.objectFactory = configuration.getObjectFactory();

    if (boundSql == null) { // issue #435, get the key before calculating the statement
      generateKeys(parameterObject);
      boundSql = mappedStatement.getBoundSql(parameterObject);
    }

    this.boundSql = boundSql;
    // ===== ↓↓↓ Step Into ↓↓↓ =====> 还会同时创建另外两个组件!!! → 组件创建: #4.8
    this.parameterHandler = configuration.newParameterHandler(
            mappedStatement, parameterObject, boundSql);
    this.resultSetHandler = configuration.newResultSetHandler(executor
            , mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}

如果看到这了,现在再回到 #4.7!看第二个要 Step Into 的地方!

4.11 PreparedStatementHandler

@Override
public void parameterize(Statement statement) throws SQLException {
    // ===== ↓↓↓ Step Into ↓↓↓ =====> #4.12
    parameterHandler.setParameters((PreparedStatement) statement);
}

@Override
public <E> List<E> query(Statement statement
        , ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    // ===== ↓↓↓ Step Into ↓↓↓ =====> #4.13
    return resultSetHandler.<E> handleResultSets(ps);
}

4.12 DefaultParameterHandler

@Override
public void setParameters(PreparedStatement ps) {
    // ...

    // TypeHandler 给 SQL 预编译设置参数
    TypeHandler typeHandler = parameterMapping.getTypeHandler();
    JdbcType jdbcType = parameterMapping.getJdbcType();
    if (value == null && jdbcType == null) {
        jdbcType = configuration.getJdbcTypeForNull();
    }
    typeHandler.setParameter(ps, i + 1, value, jdbcType);

    // ...
}

回到 #4.7,继续走第 3 个断点。

4.13 DefaultResultSetHandler

JavaBean 和表记录的映射(设置参数、结果映射) 由 TypeHandler 完成。

(1)DefaultResultSetHandler#handleResultSets

从 rsw 结果集参数中获取查询结果,再根据 resultMap 映射信息,将查询结果映射到 multipleResults 中。

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

    // <select>标签的resultMap属性,可以指定多个值,多个值之间用逗号(,)分割
    final List<Object> multipleResults = new ArrayList<>();

    int resultSetCount = 0;
    // 这里是获取第一个结果集,将传统JDBC的ResultSet包装成一个包含结果列元信息的ResultSetWrapper对象
    ResultSetWrapper rsw = getFirstResultSet(stmt);

    // 这里是获取所有要映射的ResultMap(按照逗号分割出来的)
    List<ResultMap> resultMaps = mappedStatement.getResultMaps();
    // 要映射的ResultMap的数量
    int resultMapCount = resultMaps.size();
    validateResultMapsCount(rsw, resultMapCount);
    // 循环处理每个ResultMap,从第一个开始处理
    while (rsw != null && resultMapCount > resultSetCount) {
        // 得到结果映射信息
        ResultMap resultMap = resultMaps.get(resultSetCount);
        // 处理结果集。从rsw结果集参数中获取查询结果,再根据resultMap映射信息,将查询结果映射到multipleResults中
        handleResultSet(rsw, resultMap, multipleResults, null);

        rsw = getNextResultSet(stmt);
        cleanUpAfterHandlingResultSet();
        resultSetCount++;
    }

    // 对应<select>标签的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(rsw, resultMap, null, parentMapping);
            }
            rsw = getNextResultSet(stmt);
            cleanUpAfterHandlingResultSet();
            resultSetCount++;
        }
    }

    // 如果只有一个结果集合,则直接从多结果集中取出第一个
    return collapseSingleResultList(multipleResults);
}

(2)DefaultResultSetHandler#handleRowValues

处理行数据,其实就是完成结果映射。

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

(3)DefaultResultSetHandler#handleRowValuesForSimpleResultMap

简单结果映射

private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap,
        ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
    DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
    // 获取结果集信息
    ResultSet resultSet = rsw.getResultSet();
    // 使用rowBounds的分页信息,进行逻辑分页(也就是在内存中分页)
    skipRows(resultSet, rowBounds);
    while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
        // 通过<resultMap>标签的子标签<discriminator>对结果映射进行鉴别
        ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
        // 将查询结果封装到POJO中
        Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
        // 处理对象嵌套的映射关系
        storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
    }
}

(4)DefaultResultSetHandler#getRowValue

将查询结果封装到 POJO 中

private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
    // 延迟加载的映射信息
    final ResultLoaderMap lazyLoader = new ResultLoaderMap();
    // 创建要映射的 PO 类对象
    Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
    if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
        final MetaObject metaObject = configuration.newMetaObject(rowValue);
        boolean foundValues = this.useConstructorMappings;
        // 是否应用自动映射,也就是通过 resultType 进行映射
        if (shouldApplyAutomaticMappings(resultMap, false)) {
            // 根据 columnName 和 type 属性名映射赋值
            foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
        }
        // 根据我们配置 ResultMap 的 column 和 property 映射赋值
        // 如果映射存在 nestedQueryId,会调用 getNestedQueryMappingValue 方法获取返回值
        foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
        foundValues = lazyLoader.size() > 0 || foundValues;
        rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
    }
    return rowValue;
}

(4.1)DefaultResultSetHandler#createResultObject

创建映射结果对象

private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader,
        String columnPrefix) throws SQLException {
    this.useConstructorMappings = false; // reset previous mapping result
    final List<Class<?>> constructorArgTypes = new ArrayList<>();
    final List<Object> constructorArgs = new ArrayList<>();
    // 创建结果映射的PO类对象
    Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
    if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
        // 获取要映射的PO类的属性信息
        final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
        for (ResultMapping propertyMapping : propertyMappings) {
            // 延迟加载处理
            if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {
                // 通过动态代理工厂,创建延迟加载的代理对象
                resultObject = configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration,
                        objectFactory, constructorArgTypes, constructorArgs);
                break;
            }
        }
    }
    this.useConstructorMappings = resultObject != null && !constructorArgTypes.isEmpty(); // set current mapping result
    return resultObject;
}

private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes,
        List<Object> constructorArgs, String columnPrefix) throws SQLException {
    final Class<?> resultType = resultMap.getType();
    final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory);
    final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
    if (hasTypeHandlerForResultObject(rsw, resultType)) {
        return createPrimitiveResultObject(rsw, resultMap, columnPrefix);
    } else if (!constructorMappings.isEmpty()) {
        return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes,
                constructorArgs, columnPrefix);
    } else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
        // 对象工厂创建对象
        return objectFactory.create(resultType);
    } else if (shouldApplyAutomaticMappings(resultMap, false)) {
        return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs, columnPrefix);
    }
    throw new ExecutorException("Do not know how to create an instance of " + resultType);
}

(4.2)DefaultResultSetHandler#applyAutomaticMappings

根据 columnName 和 type 属性名映射赋值

private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject,
        String columnPrefix) throws SQLException {
    List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
    boolean foundValues = false;
    if (!autoMapping.isEmpty()) {
        for (UnMappedColumnAutoMapping mapping : autoMapping) {
            final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
            if (value != null) {
                foundValues = true;
            }
            if (value != null || (configuration.isCallSettersOnNulls() && !mapping.primitive)) {
                // gcode issue #377, call setter on nulls (value is not 'found')
                metaObject.setValue(mapping.property, value);
            }
        }
    }
    return foundValues;
}

(4.3)DefaultResultSetHandler#applyPropertyMappings

根据我们配置 ResultMap 的 column 和 property 映射赋值,如果映射存在 nestedQueryId,会调用 getNestedQueryMappingValue 方法获取返回值。

private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject,
        ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
    final List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
    boolean foundValues = false;
    final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
    for (ResultMapping propertyMapping : propertyMappings) {
        String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
        if (propertyMapping.getNestedResultMapId() != null) {
            // the user added a column attribute to a nested result map, ignore it
            column = null;
        }
        if (propertyMapping.isCompositeResult()
                || (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH)))
                || propertyMapping.getResultSet() != null) {
            Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader,
                    columnPrefix);
            // issue #541 make property optional
            final String property = propertyMapping.getProperty();
            if (property == null) {
                continue;
            } else if (value == DEFERRED) {
                foundValues = true;
                continue;
            }
            if (value != null) {
                foundValues = true;
            }
            if (value != null || (configuration.isCallSettersOnNulls()
                    && !metaObject.getSetterType(property).isPrimitive())) {
                // gcode issue #377, call setter on nulls (value is not 'found')
                metaObject.setValue(property, value);
            }
        }
    }
    return foundValues;
}

(4.4)DefaultResultSetHandler#getPropertyMappingValue

private Object getPropertyMappingValue(ResultSet rs
        , MetaObject metaResultObject, ResultMapping propertyMapping
        , ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
    if (propertyMapping.getNestedQueryId() != null) {
      return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);
    } else if (propertyMapping.getResultSet() != null) {
      addPendingChildRelation(rs, metaResultObject, propertyMapping);
      return DEFERED;
    } else {
      final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
      final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
      return typeHandler.getResult(rs, column);
    }
}

4.14 小结

  1. 根据配置文件(全局、映射) 初始化出 Configuration 对象
  2. 创建一个 DefaultSqlSession 对象,其中包含 Configuration、Executor (根据全局配置文件中的 defaultExecutorType 创建出对应的 Executor) 对象的引用。
  3. DefaultSqlSession.getMapper(class),首先拿到 Mapper<I> 对应的 MapperProxyFactory,然后通过 newInstance() 创建 MapperProxy 对象,最终返回的是该对象的动态代理。
  4. 执行 CRUD 方法
    • 底层是代理对象调用了 DefaultSqlSession 对象的 CRUD 方法
    • 会创建一个 Statement 对象 (会首先创建 StatementHandler,而在 StatementHandler 的构造器中又会创建 ParameterHandler、ResultSetHandler 对象)
    • 调用 StatementHandler 预编译参数以及设置参数值(底层实际是调用 ParameterHandler 来做的)
    • 调用 StatementHandler 的 CRUD 方法
    • 使用 ResultSetHandler 封装结果

5. 总结

组件介绍:

  • SqlSession:是 Mybatis 对外暴露的核心 API,提供了对数据库的 CRUD 操作接口;
  • Executor:执行器,由 SqlSession 调用,负责数据库操作以及 Mybatis 两级缓存的维护;
  • StatementHandler:封装了 JDBC Statement 操作,负责对 Statement 的操作,例如 PrepareStatement 参数的设置以及结果集的处理;
  • ParameterHandler:是 StatementHandler 内部一个组件,主要负责对 ParameterStatement 参数的设置;
  • ResultSetHandler:是 StatementHandler 内部一个组件,主要负责对 ResultSet 结果集的处理,封装成目标对象返回;
  • TypeHandler:用于 Java 类型与 JDBC 类型之间的数据转换,ParameterHandler 和 ResultSetHandler 会分别使用到它的类型转换功能;
  • MappedStatement:是对 Mapper 配置文件或 Mapper 接口方法上通过注解声明 SQL 的封装;
  • Configuration:Mybatis 所有配置都统一由 Configuration 进行管理,内部由具体对象分别管理各自的小功能模块。

四层架构:

  • API 接口层:提供增加、删除、修改、查询等接口,通过 API 接口对数据库进行操作;
  • 数据处理层:主要负责 SQL 的查询、解析、执行以及结果映射的处理,解析 SQL 根据调用请求完成一次数据库操作;
  • 框架支撑层:负责通用基础服务支撑,包含事务管理、连接池管理、缓存管理等共用组件的封装,为上层提供基础服务支撑;
  • 引导层:引导层是配置和启动 MyBatis 配置信息的方式。

【注意】MyBatis 的四大组件创建过程中,都有插件进行介入:interceptorChain.pluginAll(...)

posted @ 2020-09-19 17:17  tree6x7  阅读(177)  评论(0编辑  收藏  举报