3. MyBatis的运行流程

MyBatis的运行流程

      • MyBatis的架构设计
      • 主要构件及其相互关系
      • MyBatis的总体流程
        • 一、加载配置并初始化
        • 二、接受调用请求
        • 三、处理操作请求
        • 四、返回处理结果
      • MyBatis源码剖析

MyBatis的架构设计

3. MyBatis的运行流程_第1张图片
我们把MyBatis的功能架构分为三层:

  1. API接口层:提供给外部使用的接口API,接口层收到调用请求就会调用数据处理层来完成具体的数据处理。MyBatis和数据库交互的方式有调用API使用Mapper 代理
  2. 数据处理层:负责具体的SQL查找,解析,执行和执行结果的映射处理
  3. 基础支撑层:负责连接管理,事务管理,配置加载和缓存处理

主要构件及其相互关系

3. MyBatis的运行流程_第2张图片
3. MyBatis的运行流程_第3张图片

MyBatis的总体流程

一、加载配置并初始化

将主配置文件内容解析封装到 configuration,将SQL的配置信息加载成为一个mappedstatement对象,存储在内存中

二、接受调用请求

调用MyBatis的api,传入sql的Id 和 参数对象,将请求传递给请求处理层进行处理

三、处理操作请求

  1. 根据sql 的id找到对应的MappedStatement对象
  2. 根据传入参数对象解析MappedStatement对象,得到最终要执行的sql和执行传入参数
  3. 连接数据库连接,根据得到的最终sql语句和执行传入参数到数据库执行,得到执行结果
  4. 根据MappedStatement对象中的结果映射配置对得到的执行结果进行转换处理,并得到最终的处理结果
  5. 释放资源连接

四、返回处理结果

返回处理结果

MyBatis源码剖析

简单来说 MyBatis 就是对我们 jdbc 的一个封装,我们使用jdbc 的时候,大值的流程步骤如下

// 加载配置文件,获取到输入流
InputStream resourceAsStream = Resources.getResourceAsStream("configuration.xml");
// 开始初始化
// 将获取到的文件输入流通过 SqlSessionFactoryBuilder 进行构建,此时是真正的初始化过程
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
// 进入 build 方法中
public SqlSessionFactory build(InputStream inputStream) {
    return build(inputStream, null, null);
}
// 可以看到下面几行代码
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
	// 通过 XMLConfigBuilder 将配置文件中的信息读取出来,然后在通过 parser.parse() 进行解析
	XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
    return build(parser.parse());
}

// XMLConfigBuilder 进行读取的时候会给一些必要数据进行初始化,包括后面用到的 parsed ,表示是否已经被解析过了
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
    super(new Configuration());
    ErrorContext.instance().resource("SQL Mapper Configuration");
    this.configuration.setVariables(props);
    this.parsed = false;
    this.environment = environment;
    this.parser = parser;
  }

public Configuration parse() {
    if (parsed) {
      throw new BuilderException("Each MapperConfigParser can only be used once.");
    }
    // 标记已经解析
    parsed = true;
    // 这个方法下会将 xml 文件中的setting,properties,typeAliases进行读取,最重要的是对 mappers 标签进行解析,将所有的mapper.xml中的select标签 insert等封装成一个mappedstatement对象,再把mappedstatement 封装到 configuration 中
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
}

// build 就是对 configuration 进行初始化的过程
public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
}
// 因此在初始化这一步骤我们已经拿到了 configuration 和 封装好的mappedstatement 

// 获取到 sqlSession和创建executor,一般我们使用的 simpleExecutor,除此之外还有batchExecutor
SqlSession sqlSession = sqlSessionFactory.openSession();
// 通过拿到的 SqlSession去执行sql语句,sql语句的执行器是上一步获取到的 simpleExecutor 来进行操作的
// executor 首先会先尝试在一级缓存中获取数据
// 具体的操作语句是使用 StatementHandler 进行完成的
// 首先根据StatementHandler获取到数据库的连接信息,然后使用 
List<Object> objects = sqlSession.selectList("");

public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    BoundSql boundSql = ms.getBoundSql(parameter);
    // 创建一级缓存 key
    CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
    // 查询操作
    return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}

// 具体的 query 操作
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
   ....
    try {
      queryStack++;
      // localCache.getObject(key) 根据 key 获取到一级缓存的数据
      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);
      }
    }
    ....
    return list;
}

private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    // 直接看 doQuery 方法,点击选择 simpleExecutor
     list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
}
// 创建 StatementHandler ,通过 prepareStatement 给 StatementHandler 设置数据库连接参数
// 然后交由 StatementHandler  去具体的执行sql
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(this, ms, parameter, rowBounds, resultHandler, boundSql);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.<E>query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }

  public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
    return Collections.emptyList();
  }

  private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    Connection connection = getConnection(statementLog);
    stmt = handler.prepare(connection);
    handler.parameterize(stmt);
    return stmt;
  }

你可能感兴趣的:(MyBatis学习笔记)