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

本文涉及的产品
云解析 DNS,旗舰版 1个月
云解析DNS,个人版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 上一篇我们对 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拿来直接套用就好,没有的话就需要搭建框架,再把框架存入本地类库中,再进行解析。

相关文章
|
7天前
|
XML 前端开发 Java
Mybatis-Plus乐观锁配置
Mybatis-Plus乐观锁配置
14 1
|
8天前
|
SQL Java 数据库连接
Mybatis中一对多mapper配置
Mybatis中一对多mapper配置
13 0
|
12天前
|
Java Spring
mybatisplus的typeAliasesPackage 配置
【6月更文挑战第20天】mybatisplus的typeAliasesPackage 配置
16 3
|
13天前
|
Java 数据库连接 Apache
JavaWeb基础第二章(Maven项目与MyBatis 的快速入门与配置)
JavaWeb基础第二章(Maven项目与MyBatis 的快速入门与配置)
|
16天前
|
SQL 人工智能 Java
mybatis-plus配置sql拦截器实现完整sql打印
_shigen_ 博主分享了如何在MyBatis-Plus中打印完整SQL,包括更新和查询操作。默认日志打印的SQL用?代替参数,但通过自定义`SqlInterceptor`可以显示详细信息。代码示例展示了拦截器如何替换?以显示实际参数,并计算执行时间。配置中添加拦截器以启用此功能。文章提到了分页查询时的限制,以及对AI在编程辅助方面的思考。
51 5
mybatis-plus配置sql拦截器实现完整sql打印
|
2月前
|
XML Java 数据库连接
【MyBatisPlus】快速入门、常用注解、常用配置
【MyBatisPlus】快速入门、常用注解、常用配置
25 0
|
2月前
|
SQL 安全 BI
基于jeecg-boot的nbcio-boot因升级mybatis-plus到3.5.3.1和JSQLParser 到4.6而引起的在线报表配置报错处理
基于jeecg-boot的nbcio-boot因升级mybatis-plus到3.5.3.1和JSQLParser 到4.6而引起的在线报表配置报错处理
55 0
|
2月前
|
SQL Java 数据库连接
【Mybatis】深入学习MyBatis:概述、主要特性以及配置与映射
【Mybatis】深入学习MyBatis:概述、主要特性以及配置与映射
【Mybatis】深入学习MyBatis:概述、主要特性以及配置与映射
|
2月前
|
Java 数据库连接 数据库
MyBatis之旅:从零开始的环境搭建与配置
MyBatis之旅:从零开始的环境搭建与配置
45 1
|
2月前
|
XML SQL Java
mybatis的一对多,多对一,以及多对对的配置和使用
mybatis的一对多,多对一,以及多对对的配置和使用
24 2