MyBatis 核心配置综述之 Executor(下)

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: 上一篇我们对 SqlSession 和 SqlSessionFactory 的创建过程有了一个详细的了解,可以去是看 MyBatis 基础搭建及架构概述但上述的创建过程只是为 SQL 执行和 SQL 映射做了基础的铺垫而已,就和我们 Spring 源码为 Bean 容器的加载进行许多初始化的工作相同,那么做好前期的准备工作接下来该做什么了呢?该做数据库连接驱动管理和 SQL 解析工作了!那么本篇本章就来讨论一下数据库驱动连接管理和SQL解析的管理组件之 Executor 执行器。

35.jpgBoundSql这个类包括 SQL 的基本信息,基本的 SQL 语句,参数映射,参数类型等

36.jpg

上述的 query 方法会调用到 CachingExecutor 类中的 query 查询缓存的方法

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.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
        tcm.putObject(cache, key, list); 
      }
      return list;
    }
  }
  // 委托模式,交给SimpleExecutor等实现类去实现方法。
  return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

由 delegate 执行 query 方法,delegate 即是 BaseExecutor,然后由具体的执行器去真正执行 query 方法

注意:源码中一般以 do** 开头的方法都是真正加载执行的方法

// 经过一系列的调用,会调用到下面的方法(与主流程无关,故省略)
// 以SimpleExecutor简单执行器为例
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,解析SQL语句
    StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
    stmt = prepareStatement(handler, ms.getStatementLog());
    // 由handler来对SQL语句执行解析工作
    return handler.<E>query(stmt, resultHandler);
  } finally {
    closeStatement(stmt);
  }
}

由上面的源码可以看出,Executor 执行器所起的作用相当于是管理 StatementHandler 的整个生命周期的工作,包括创建、初始化、解析、关闭。

ReuseExecutor 完成的 doQuery 工作:几乎和 SimpleExecutor 完成的工作一样,其内部不过是使用一个 Map 来存储每次执行的查询语句,为后面的 SQL 重用作准备。

BatchExecutor 完成的 doQuery 工作和 SimpleExecutor 完成的工作一样。

update() 方法

在分析完上面的查询方法后,我们再来聊一下update()方法,update() 方法不仅仅指的是update() 方法,它是一条 update 链,什么意思呢?就是 *insert、update、delete 在语义上其实都是更新的意思,而查询在语义上仅仅只是表示的查询,那么我们来偷窥一下 update方法的执行流程,与 select 的主要执行流程很相似,所以一次性贴出。

// 首先在顶级接口中定义update 方法,交由子类或者抽象子类去实现
// 也是首先去缓存中查询是否具有已经执行过的相同的update语句
public int update(MappedStatement ms, Object parameterObject) throws SQLException {
  flushCacheIfRequired(ms);
  return delegate.update(ms, parameterObject);
}
// 然后再交由BaseExecutor 执行update 方法
public int update(MappedStatement ms, Object parameter) throws SQLException {
  ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
  if (closed) {
    throw new ExecutorException("Executor was closed.");
  }
  clearLocalCache();
  return doUpdate(ms, parameter);
}
// 往往do* 开头的都是真正执行解析的方法,所以doUpdate 应该就是真正要执行update链的解析方法了
// 交给具体的执行器去执行
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
  Statement stmt = null;
  try {
    Configuration configuration = ms.getConfiguration();
    StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
    stmt = prepareStatement(handler, ms.getStatementLog());
    return handler.update(stmt);
  } finally {
    closeStatement(stmt);
  }
}

ReuseExecutor 完成的 doUpdate 工作:几乎和 SimpleExecutor完成的工作一样,其内部不过是使用一个Map来存储每次执行的更新语句,为后面的SQL重用作准备。

BatchExecutor 完成的 doUpdate 工作:和 SimpleExecutor 完成的工作相似,只是其内部有一个 List 列表来一次行的存储多个 Statement,用于将多个 sql 语句一次性输送到数据库执行。

queryCursor()方法

我们查阅其源码的时候,在执行器的执行过程中并没有发现其与 query 方法有任何不同之处,但是在 doQueryCursor 方法中我们可以看到它返回了一个 cursor 对象,网上搜索cursor 的相关资料并查阅其基本结构,得出来的结论是:用于逐条读取 SQL 语句,应对数据量

// 查询可以返回Cursor<T>类型的数据,类似于JDBC里的ResultSet类,
// 当查询百万级的数据的时候,使用游标可以节省内存的消耗,不需要一次性取出所有数据,可以进行逐条处理或逐条取出部分批量处理。
public interface Cursor<T> extends Closeable, Iterable<T> {
    boolean isOpen();
    boolean isConsumed();
    int getCurrentIndex();
}

flushStatements() 方法

flushStatement() 的主要执行流程和 query,update 的执行流程差不多,我们这里就不再详细贴代码了,简单说一下 flushStatement() 的主要作用,flushStatement() 主要用来释放 statement,或者用于 ReuseExecutor 和 BatchExecutor 来刷新缓存。

createCacheKey() 方法

createCacheKey() 方法主要由 BaseExecutor 来执行并创建缓存,MyBatis 中的缓存分为一级缓存和二级缓存,关于缓存的讨论我们将在 Mybatis 系列的缓存章节。

Executor 中的其他方法

Executor 中还有其他方法,提交 commit,回滚 rollback,判断是否时候缓存 isCached,关闭 close,获取事务 getTransaction 立即清除本地缓存 clearLocalCache 等。

Executor 的现实抽象

在上面的分析过程中我们了解到,Executor 执行器是 MyBatis 中很重要的一个组件,Executor 相当于是外包的 boss,它定义了甲方(SQL)需要干的活(Executor的主要方法),这个外包公司是个小公司,没多少人,每个人都需要干很多工作,boss 接到开发任务的话,一般都找项目经理(CachingExecutor),项目经理几乎不懂技术,它主要和技术leader(BaseExecutor)打交道,技术 leader 主要负责框架的搭建,具体的工作都会交给下面的程序员来做,程序员的技术也有优劣,高级程序员(BatchExecutor)、中级程序员(ReuseExecutor)、初级程序员(SimpleExecutor),它们干的活也不一样。一般有新的项目需求传达到项目经理这里,项目经理先判断自己手里有没有现成的类库或者项目直接套用(Cache),有的话就直接让技术leader拿来直接套用就好,没有的话就需要搭建框架,再把框架存入本地类库中,再进行解析。

相关文章
|
13天前
|
缓存 NoSQL Java
Mybatis学习:Mybatis缓存配置
MyBatis缓存配置包括一级缓存(事务级)、二级缓存(应用级)和三级缓存(如Redis,跨JVM)。一级缓存自动启用,二级缓存需在`mybatis-config.xml`中开启并配置映射文件或注解。集成Redis缓存时,需添加依赖、配置Redis参数并在映射文件中指定缓存类型。适用于查询为主的场景,减少增删改操作,适合单表操作且表间关联较少的业务。
|
4月前
|
SQL XML Java
mybatis复习01,简单配置让mybatis跑起来
文章介绍了MyBatis的基本概念、历史和特点,并详细指导了如何配置MyBatis环境,包括创建Maven项目、添加依赖、编写核心配置文件、创建数据表和实体类、编写Mapper接口和XML配置文件,以及如何编写工具类和测试用例。
mybatis复习01,简单配置让mybatis跑起来
|
5月前
|
安全 Java 数据库连接
后端框架的学习----mybatis框架(3、配置解析)
这篇文章详细介绍了MyBatis框架的核心配置文件解析,包括环境配置、属性配置、类型别名设置、映射器注册以及SqlSessionFactory和SqlSession的生命周期和作用域管理。
后端框架的学习----mybatis框架(3、配置解析)
|
4月前
|
SQL XML Java
mybatis :sqlmapconfig.xml配置 ++++Mapper XML 文件(sql/insert/delete/update/select)(增删改查)用法
当然,这些仅是MyBatis功能的初步介绍。MyBatis还提供了高级特性,如动态SQL、类型处理器、插件等,可以进一步提供对数据库交互的强大支持和灵活性。希望上述内容对您理解MyBatis的基本操作有所帮助。在实际使用中,您可能还需要根据具体的业务要求调整和优化SQL语句和配置。
82 1
|
5月前
|
缓存 Java 数据库连接
mybatis1.常见配置
本文介绍了MyBatis框架中的常见配置及其加载顺序。配置可通过`properties`元素、资源文件或方法参数传递,其中方法参数传递的属性具有最高优先级。文章列举了几个重要的配置项,如`cacheEnabled`用于全局开启或关闭缓存功能;`lazyLoadingEnabled`控制对象的延迟加载行为;`useGeneratedKeys`允许JDBC支持自动生成主键;`defaultExecutorType`设定默认执行器类型等。此外,还介绍了多环境配置方法,通过`environments`元素可定义不同环境下的数据库连接信息,并可根据需求动态选择加载特定环境
|
6月前
|
SQL Java 数据库连接
idea中配置mybatis 映射文件模版及 mybatis plus 自定义sql
idea中配置mybatis 映射文件模版及 mybatis plus 自定义sql
154 3
|
6月前
|
Java 数据库连接 mybatis
SpringBoot配置Mybatis注意事项,mappers层下的name命名空间,要落实到Dao的video类,resultType要落到bean,配置好mybatis的对应依赖。
SpringBoot配置Mybatis注意事项,mappers层下的name命名空间,要落实到Dao的video类,resultType要落到bean,配置好mybatis的对应依赖。
|
7月前
|
XML 前端开发 Java
Mybatis-Plus乐观锁配置
Mybatis-Plus乐观锁配置
若依修改,集成mybatisplus报错,若依集成mybatisplus,总是找不到映射是怎么回事只要是用mp的方法就找报,改成mybatisPlus配置一定要改
若依修改,集成mybatisplus报错,若依集成mybatisplus,总是找不到映射是怎么回事只要是用mp的方法就找报,改成mybatisPlus配置一定要改
接口模板,文本常用的接口Controller层,常用的controller层模板,Mybatisplus的相关配置
接口模板,文本常用的接口Controller层,常用的controller层模板,Mybatisplus的相关配置