mybatis执行流程

mybatis执行流程

img

MyBatis执行八步走

上面流程就是MyBatis内部核心流程,咱们来一步步解释下,根据图中步骤,我们可以将这个执行流程分成了8个步骤。

1、读取MyBatis的核心配置文件。

mybatis-config.xml为MyBatis的全局配置文件,用于配置数据库连接、属性、类型别名、类型处理器、插件、环境配置、映射器(mapper.xml)等信息,这个过程中有一个比较重要的部分就是映射文件其实是配在这里的;这个核心配置文件最终会被封装成一个Configuration对象

2、加载映射文件。

映射文件即SQL映射文件,该文件中配置了操作数据库的SQL语句,映射文件是在mybatis-config.xml中加载;可以加载多个映射文件。常见的配置的方式有两种,一种是package扫描包,一种是mapper找到配置文件的位置。

[复制代码](javascript:void(0)😉

<!-- 使用包路径,扫描包下所有的接口,这种方式比较方便 --> 

<package name="com.mybatis.demo"/> 
<!-- resource:使用相对路径的资源引用-->
<!-- url:使用绝对类路径的资源引用-->
<!-- class:使用映射器接口实现类的完全限定类名-->
<mapper resource="xxx.xml"/>

[复制代码](javascript:void(0)😉

3、构造会话工厂获取SqlSessionFactory。

这个过程其实是用建造者设计模式使用SqlSessionFactoryBuilder对象构建的,SqlSessionFactory的最佳作用域是应用作用域。

//2. 创建SqlSessionFactory对象实际创建的是DefaultSqlSessionFactory对象
SqlSessionFactory builder = new    SqlSessionFactoryBuilder().build(inputStream);

4、创建会话对象SqlSession。

由会话工厂创建SqlSession对象,对象中包含了执行SQL语句的所有方法,每个线程都应该有它自己的 SqlSession 实例。SqlSession的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 并把执行器放进SqlSession中

//3. 创建SqlSession对象实际创建的是DefaultSqlSession对象
  SqlSession sqlSession = builder.openSession();

5、Executor执行器。

是MyBatis的核心,负责SQL语句的生成和查询缓存的维护,它将根据SqlSession传递的参数动态地生成需要执行的SQL语句,同时负责查询缓存的维护

  • SimpleExecutor -- SIMPLE 就是普通的执行器。
  • ReuseExecutor-执行器会重用预处理语句(PreparedStatements)
  • BatchExecutor --它是批处理执行器
1.CachingExecutor 二级缓存执行器

里面修饰了一个BaseExecutor执行器,上面是他的实现类,delegate.query执行上面执行器的.query方法

  @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, 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);
  }
2.BaseExecutor执行器

先查询一级缓存,如果一级缓存有,则直接返回缓存中的数据。如果一级缓存没有,则查询数据库queryFromDatabase

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

3SimpleExector执行器

在执行到查询数据库后,后面会调用执行器的查询数据库方法,

  @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());
      return handler.query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }

StatementHandler里面有2个属性,parameterHandler处理入参, resultSetHandler处理返回结果

@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
  String sql = boundSql.getSql();
  statement.execute(sql);
  //设置结果,结果处理器resultSetHandler
  return resultSetHandler.handleResultSets(statement);
}

6、MappedStatement对象。

MappedStatement是对解析的SQL的语句封装,一个MappedStatement代表了一个sql语句标签,如下:

<!--一个动态sql标签就是一个`MappedStatement`对象-->
<select    id="selectUserList"    resultType="com.mybatis.User"> 
  select * from t_user
</select>

7、输入参数映射

输入参数类型可以是基本数据类型,也可以是Map、List、POJO类型复杂数据类型,这个过程类似于JDBC的预编译处理参数的过程,有两个属性 parameterType和parameterMap

8、封装结果集。

可以封装成多种类型可以是基本数据类型,也可以是Map、List、POJO类型复杂数据类型。封装结果集的过程就和JDBC封装结果集是一样的。也有两个常用的属性resultType和resultMap。

posted on   共感的艺术  阅读(2089)  评论(0编辑  收藏  举报
努力加载评论中...

点击右上角即可分享
微信分享提示