Mybatis源码分析

一、引言

  之前的文章已经介绍mybatis的架构跟源码的构建构成,这篇文章会根据之前的测试类来调试解析源码。

二、创建SqlSessionFactory

      SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);

reader是读取的我们的mybatis-config配置文件,主要看一下build方法

  public SqlSessionFactory build(Reader reader) {
    return build(reader, null, null);
  }
  public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
    try {
      //建造者模式,构建XMLConfigBuilder,用来解析mybatis全局配置文件的对象
      XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
      //解析配置文件
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        reader.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }

创建xml解析器

  public XMLConfigBuilder(Reader reader, String environment, Properties props) {
    //创建XPathParser,用来解析xml
    this(new XPathParser(reader, true, props, new XMLMapperEntityResolver()), environment, props);
  }

解析配置文件

  public SqlSessionFactory build(Configuration config) {
    //将解析后得到的配置对象放入DefaultSqlSessionFactory
    return new DefaultSqlSessionFactory(config);
  }
  
  public Configuration parse() {
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    //标志位
    parsed = true;
    //mybatis配置文件的根节点configuration
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }

解析标签

  private void parseConfiguration(XNode root) {
    try {
      // issue #117 read properties first
      //解析properties标签
      propertiesElement(root.evalNode("properties"));
      //解析settings的标签
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      //vfs 虚拟文件系统
      loadCustomVfs(settings);
      //log日志,如果配置了LogImpl,会设置到LogFactory中去
      loadCustomLogImpl(settings);
      //别名
      typeAliasesElement(root.evalNode("typeAliases"));
      // plugin
      //插件
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      //环境的配置,例如:是否开启二级缓存等等
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      //环境
      //在Mybatis中支持我们根据不同的环境进行配置不同的数据库,这些配置会放到environments节点下
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      //类型处理器
      typeHandlerElement(root.evalNode("typeHandlers"));
      //解析mapper节点配置
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }

以上过程就是初始化构建环境,比较简单,我们挑一个mapper标签解析看一下

    //4种配置方式
  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 {
          // 获取resource属性
          String resource = child.getStringAttribute("resource");
          // 获取url属性
          String url = child.getStringAttribute("url");
          // 获取class属性
          String mapperClass = child.getStringAttribute("class");
          if (resource != null && url == null && mapperClass == null) {
            ErrorContext.instance().resource(resource);
            try(InputStream inputStream = Resources.getResourceAsStream(resource)) {
              // 创建XMLMapperBuilder对象
              XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
              // 解析映射文件
              mapperParser.parse();
            }
          } else if (resource == null && url != null && mapperClass == null) {
            ErrorContext.instance().resource(url);
            try(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.");
          }
        }
      }
    }
  }

mapper标签大的类型可以分成两种:配置package和配置资源文件,资源文件又可分为3种resource、url、class,都是为了找到具体的mapper.xml文件,然后解析mapperParser.parse()。

  public void parse() {
    // 判断是否已经加载过该映射文件
    if (!configuration.isResourceLoaded(resource)) {
      // 处理mapper节点
      configurationElement(parser.evalNode("/mapper"));
      // 将映射文件记录到Configuration.loadedResources字段中   是一个Set
      configuration.addLoadedResource(resource);
      // 注册Mapper
      bindMapperForNamespace();
    }
    // 处理解析失败的ResultMap
    parsePendingResultMaps();
    // 处理解析失败的cache-ref
    parsePendingCacheRefs();
    // 处理解析失败的SQL
    parsePendingStatements();
  }

处理mapper文件

  private void configurationElement(XNode context) {
    try {
      // 获取namespace属性
      String namespace = context.getStringAttribute("namespace");
      // namespace不存在抛出异常
      if (namespace == null || namespace.isEmpty()) {
        throw new BuilderException("Mapper's namespace cannot be empty");
      }
      // 设置builderAssistant字段的currentNamespace属性
      builderAssistant.setCurrentNamespace(namespace);
      // 解析cache-ref节点
      cacheRefElement(context.evalNode("cache-ref"));
      // 解析cache节点
      cacheElement(context.evalNode("cache"));
      //入参
      parameterMapElement(context.evalNodes("/mapper/parameterMap"));
      //返回值
      resultMapElements(context.evalNodes("/mapper/resultMap"));
      //sql片段
      sqlElement(context.evalNodes("/mapper/sql"));
      //sql语句
      buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);
    }
  }

cache-ref

  private void cacheRefElement(XNode context) {
    if (context != null) {
      // Configuration.cacheRefMap属性中添加数据   当前命名空间和节点的namespace属性进行关联
      configuration.addCacheRef(builderAssistant.getCurrentNamespace(), context.getStringAttribute("namespace"));
      // 创建CacheRefResolver对象
      CacheRefResolver cacheRefResolver = new CacheRefResolver(builderAssistant, context.getStringAttribute("namespace"));
      try {
        // 解析cacheRef
        cacheRefResolver.resolveCacheRef();
      } catch (IncompleteElementException e) {
        // 如果解析发生异常添加到incompleteCacheRef字段中
        configuration.addIncompleteCacheRef(cacheRefResolver);
      }
    }
  } 

cache

  private void cacheElement(XNode context) {
    if (context != null) {
      // 获取type属性  默认为PERPETUAL
      String type = context.getStringAttribute("type", "PERPETUAL");
      // 通过别名获取对应的类型
      Class<? extends Cache> typeClass = typeAliasRegistry.resolveAlias(type);
      // 获取eviction属性  默认为LRU
      String eviction = context.getStringAttribute("eviction", "LRU");
      // 获取eviction别名对应的类型
      Class<? extends Cache> evictionClass = typeAliasRegistry.resolveAlias(eviction);
      // 获取flushInterval属性
      Long flushInterval = context.getLongAttribute("flushInterval");
      // 获取size属性
      Integer size = context.getIntAttribute("size");
      // 获取redaOnly属性  默认为false
      boolean readWrite = !context.getBooleanAttribute("readOnly", false);
      // 获取blocking属性  默认为false
      boolean blocking = context.getBooleanAttribute("blocking", false);
      // 获取子节点数据
      Properties props = context.getChildrenAsProperties();
      // 创建Cache对象并添加到Configuration.caches中
      builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, blocking, props);
    }
  }
  public Cache useNewCache(Class<? extends Cache> typeClass,
      Class<? extends Cache> evictionClass,
      Long flushInterval,
      Integer size,
      boolean readWrite,
      boolean blocking,
      Properties props) {
    // 创建Cache对象
    Cache cache = new CacheBuilder(currentNamespace)
        .implementation(valueOrDefault(typeClass, PerpetualCache.class))
        .addDecorator(valueOrDefault(evictionClass, LruCache.class))
        .clearInterval(flushInterval)
        .size(size)
        .readWrite(readWrite)
        .blocking(blocking)
        .properties(props)
        .build();
    // 将cache添加到configuration中
    configuration.addCache(cache);
    // 记录当前命名空间使用的cache
    currentCache = cache;
    return cache;
  }

cache和cache-ref节点的解析最后都会修改MapperBuilderAssistant.currentCache属性的值,因此,当这两个标签都存在时会存在覆盖的问题。

解析sql语句

  private void buildStatementFromContext(List<XNode> list) {
    if (configuration.getDatabaseId() != null) {
      buildStatementFromContext(list, configuration.getDatabaseId());
    }
    buildStatementFromContext(list, null);
  }
  
  private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
    //循环解析sql语句
    for (XNode context : list) {
      final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
      try {
        statementParser.parseStatementNode();
      } catch (IncompleteElementException e) {
        configuration.addIncompleteStatement(statementParser);
      }
    }
  }
  
  public void parseStatementNode() {

    // 获取id属性
    String id = context.getStringAttribute("id");
    // 获取databaseId属性
    String databaseId = context.getStringAttribute("databaseId");
    // 获取到的databaseId和创建时设置的databaseId不一致   不处理
    if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
      return;
    }
    // 获取节点名称
    String nodeName = context.getNode().getNodeName();
    // 获取sql类型
    SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
    //判断是否为select节点
    boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
    // 是否刷新缓存
    boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);
    // 是否使用缓存
    boolean useCache = context.getBooleanAttribute("useCache", isSelect);
    boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false);

    // 处理include节点
    XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
    includeParser.applyIncludes(context.getNode());

    // 获取parameterType属性
    String parameterType = context.getStringAttribute("parameterType");
    // 获取parameterType类型
    Class<?> parameterTypeClass = resolveClass(parameterType);
    // 获取lang属性
    String lang = context.getStringAttribute("lang");
    // 获取LanguageDriver对象
    LanguageDriver langDriver = getLanguageDriver(lang);

    // selectKey节点
    processSelectKeyNodes(id, parameterTypeClass, langDriver);

    //解析sql
    KeyGenerator keyGenerator;
    String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
    keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);
    if (configuration.hasKeyGenerator(keyStatementId)) {
      keyGenerator = configuration.getKeyGenerator(keyStatementId);
    } else {
      keyGenerator = context.getBooleanAttribute("useGeneratedKeys",
          configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))
          ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
    }

    SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
    //按照我们写的语句标签,解析成一个个节点,sqlNode
    StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
    Integer fetchSize = context.getIntAttribute("fetchSize");
    Integer timeout = context.getIntAttribute("timeout");
    String parameterMap = context.getStringAttribute("parameterMap");
    String resultType = context.getStringAttribute("resultType");
    Class<?> resultTypeClass = resolveClass(resultType);
    String resultMap = context.getStringAttribute("resultMap");
    String resultSetType = context.getStringAttribute("resultSetType");
    ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);
    if (resultSetTypeEnum == null) {
      resultSetTypeEnum = configuration.getDefaultResultSetType();
    }
    String keyProperty = context.getStringAttribute("keyProperty");
    String keyColumn = context.getStringAttribute("keyColumn");
    String resultSets = context.getStringAttribute("resultSets");
    //创建MappedStatement对象
    builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
        fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
        resultSetTypeEnum, flushCache, useCache, resultOrdered,
        keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
  }

三、获取SqlSession

SqlSession sqlSession = sqlSessionFactory.openSession()

  public SqlSession openSession() {
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
  }
  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      // 获取environment
      final Environment environment = configuration.getEnvironment();
      // 获取事务工厂
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      // 创建事务对象
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      // 创建执行器对象
      final Executor executor = configuration.newExecutor(tx, execType);
      // 返回一个DefaultSqlSession对象
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      // may have fetched a connection so lets call close()
      closeTransaction(tx);
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

比较重要的是执行器的创建,也是后面用来执行sql的四大对象之一,executorType 是在初始化时配置进去的。

  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) {
      //包装成CachingExecutor
      executor = new CachingExecutor(executor);
    }
    // 拦截器执行
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }

 

SimpleExecutor:每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。
ReuseExecutor:执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map内,供下一次使用。简言之,就是重复使用Statement对象。
BatchExecutor:执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。

 

自定义插件的代理初始化,前提我们自定义了插件,并配置到了配置文件中

  <plugins>
    <plugin interceptor="com.ren.mybatis.plugin.PrintSqlPlugin">
    </plugin>
  </plugins>

我们这里自定义了一个打印sql语句的插件

@Intercepts({@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class}),
  @Signature(type = StatementHandler.class, method = "update", args = {Statement.class}),
  @Signature(type = StatementHandler.class, method = "batch", args = {Statement.class})})
public class PrintSqlPlugin implements Interceptor {
  @Override
  public Object intercept(Invocation invocation) throws Throwable {
    Object target = invocation.getTarget();
    long startTime = System.currentTimeMillis();
    StatementHandler statementHandler = (StatementHandler) target;
    try {
      return invocation.proceed();
    } finally {
      long endTime = System.currentTimeMillis();
      long sqlCost = endTime - startTime;

      BoundSql boundSql = statementHandler.getBoundSql();
      String sql = boundSql.getSql();
      Object parameterObject = boundSql.getParameterObject();
      List<ParameterMapping> parameterMappingList = boundSql.getParameterMappings();

      // 格式化Sql语句,去除换行符,替换参数
      sql = formatSql(sql, parameterObject, parameterMappingList);

      System.out.println("SQL:[" + sql + "] use: [" + sqlCost + "ms]");
    }
  }

  @Override
  public Object plugin(Object target) {
    return Plugin.wrap(target, this);
  }

    ```
}

执行插件的plugin方法,会生成动态代理对象

  public Object pluginAll(Object target) {
    for (Interceptor interceptor : interceptors) {
        //执行插件的plugin方法
      target = interceptor.plugin(target);
    }
    return target;
  }
  
  //PrintSqlPlugin
  public Object plugin(Object target) {
    return Plugin.wrap(target, this);
  }
  
  public static Object wrap(Object target, Interceptor interceptor) {
    Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
    Class<?> type = target.getClass();
    Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
    if (interfaces.length > 0) {
      //根据自定义插件的注解生成相应的代理类
      return Proxy.newProxyInstance(
          type.getClassLoader(),
          interfaces,
          new Plugin(target, interceptor, signatureMap));
    }
    return target;
  }

四、SQL执行

PetUser petUser = (PetUser)sqlSession.selectOne("com.ren.mybatis.mapper.PetUserMapper.selectById","1")

  public <T> T selectOne(String statement, Object parameter) {
    List<T> list = this.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;
    }
  }
  public <E> List<E> selectList(String statement, Object parameter) {
    return this.selectList(statement, parameter, RowBounds.DEFAULT);
  }
  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    return selectList(statement, parameter, rowBounds, Executor.NO_RESULT_HANDLER);
  }
  
   private <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
    try {
      //获取MappedStatement对象,里面包含了初始化时解析好的sql信息
      MappedStatement ms = configuration.getMappedStatement(statement);
      //wrapCollection(parameter)包装了入参,通过执行器执行sql
      return executor.query(ms, wrapCollection(parameter), rowBounds, handler);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

执行器执行CachingExecutor

  public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    //获取执行的sql,就是根据之前初始化时,构建的多层sqlNode,递归解析,最终生成我们需要执行的sql语句,还未替换参数,只是替换成了?
    BoundSql boundSql = ms.getBoundSql(parameterObject);
    //创建缓存的key=statementId+offset+limit+sql+paramValueList+environmentId
    CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
    //执行查询
    return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

执行查询

  public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
      throws SQLException {
    Cache cache = ms.getCache();
    //是否配置了缓存<cache></cache>
    if (cache != null) {
      flushCacheIfRequired(ms);
      if (ms.isUseCache() && resultHandler == null) {
        ensureNoOutParams(ms, boundSql);
        //先去二级缓存中取
        @SuppressWarnings("unchecked")
        List<E> list = (List<E>) tcm.getObject(cache, key);
        if (list == null) {
          //二级缓存没有获取到,去数据库查询
          list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
          //放入到二级缓存
          tcm.putObject(cache, key, list); // issue #578 and #116
        }
        return list;
      }
    }
    //没有开启缓存,直接去数据库查询
    return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

去数据库执行查询,走的父类BaseExecutor

  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());
    //sqlSession已经关闭则报错
    if (closed) {
      throw new ExecutorException("Executor was closed.");
    }
    //如果需要清空本地缓存,则清除
    if (queryStack == 0 && ms.isFlushCacheRequired()) {
      clearLocalCache();
    }
    List<E> list;
    try {
      //从一级缓存中获取结果
      queryStack++;
      list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
      //获取到则进行处理
      if (list != null) {
        handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
      } else {
        //从数据库查询
        list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
      }
    } finally {
      queryStack--;
    }
    if (queryStack == 0) {
      for (DeferredLoad deferredLoad : deferredLoads) {
        deferredLoad.load();
      }
      // issue #601
      deferredLoads.clear();
      if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
        // issue #482
        clearLocalCache();
      }
    }
    return list;
  }

一级缓存使用的地方,然后开始进行从数据库查询

  private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    List<E> list;
    localCache.putObject(key, EXECUTION_PLACEHOLDER);
    try {
      //走子类的查询
      list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
    } finally {
      localCache.removeObject(key);
    }
    //放入一级缓存
    localCache.putObject(key, list);
    if (ms.getStatementType() == StatementType.CALLABLE) {
      localOutputParameterCache.putObject(key, parameter);
    }
    return list;
  }

又回到子类的查询

  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,还可能创建代理
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      //预处理,主要就是开始替换参数
      stmt = prepareStatement(handler, ms.getStatementLog());
      //执行查询之前,如果我们自定义了插件,会先走我们自定义的插件的intercept
      return handler.query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }

创建StatementHandler对象,预处理,执行查询之前如果配置了插件,会执行插件的intercept方法,再执行数据库查询操作

  public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    //创建StatementHandler,如有plugin还会创建代理
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return 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());
    }
    
  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;
    //先创建ParameterHandler,有添加plugin,会创建代理
    this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
    //再创建ResultSetHandler,有添加plugin,会创建代理
    this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
  }

执行查询完成之后,处理结果集

  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    //处理结果集
    return resultSetHandler.handleResultSets(ps);
  }

处理完结果集,再放回一级缓存,二级缓存。

五、关闭sqlSession

sqlSession.close()

  public void close() {
    try {
      //关闭SqlSession
      executor.close(isCommitOrRollbackRequired(false));
      //关闭游标
      closeCursors();
      dirty = false;
    } finally {
      ErrorContext.instance().reset();
    }
  }

关闭SqlSession

  public void close(boolean forceRollback) {
    try {
      try {
        //判断是否需要事务回滚操作
        rollback(forceRollback);
      } finally {
        if (transaction != null) {
          //关闭事务
          transaction.close();
        }
      }
    } catch (SQLException e) {
      // Ignore. There's nothing that can be done at this point.
      log.warn("Unexpected exception on closing transaction.  Cause: " + e);
    } finally {
      transaction = null;
      deferredLoads = null;
      //清空缓存
      localCache = null;
      localOutputParameterCache = null;
      //重置sqlSession标志
      closed = true;
    }
  }
posted @ 2022-09-14 10:10  上官兰夏  阅读(157)  评论(0)    收藏  举报