MyBatis核心组件Executor(一)

Executor: 是MyBaits核心接口之一,定义了数据库操作最基本的方法, SqlSession的功能都是基于它来实现的。


我们在 浅谈MyBatis中的SqlSession 中,知道了我们通过Mapper接口去访问数据库,通过 MyBatis binding模块分析 也知道了其实最终都是有SqlSession去执行了,但是我们在跟踪源码的时候发现,其实我们的SqlSession也没有真正的都连接数据库进行处理,它借助了我们的Executor类去完成的,如我们以查询为例所说的过程
在这里插入图片描述
在这里插入图片描述


这里我们由上述Executor类的query方法来了解下它的基础实现类BaseExecutor类


这里它首先有我们的MappedStatement获取我们的Mapper中的SQL信息,还组装成了CacheKey,这里的MappeedStatement我们在 MyBatis初始化阶段 中已有介绍,CacheKey在我们的 MyBatis缓存模块分析 也是有相关介绍的。
在这里插入图片描述

这里它在查询之前会先判断是否设置了禁用一级缓存,要是禁用的话,它在去缓存之前会先清除一级缓存,然后再查询数据库之前它会从一级缓存中去数据,没有拿到数据的话,才会去访问数据库。
在这里插入图片描述
在这里插入图片描述

在访问数据库取得数据后,它会将数据放入一级缓存之中去
在这里插入图片描述

我们会发现在BaseExecutor类真正去查询数据库的方法是没有实现的,这里只是提供的缓存管理的能力,这是一查询为例,BaseExecutor类在插入更新等操作中也是不进行访问数据库中,它主要提供事务管理的能力。


其实真正执行查询数据库的处理其实是由BaseExecutor的子类进行实现的,是不是想到了我们的 抽象类应用——模板模式
在这里插入图片描述


我们BaseExecutor类的doQuery方法共有三个实现类,如下:

  • SimpleExecutor: 默认配置,使用PrepareStatement对象访问数据库,每次访问都要创建新的PrepareStatement对象
  • ReuseExecutor: 使用预编译PrepareStatement对象访问数据库, 访问时,会重用缓存中的statement对象
  • BatchExecutor: 实现批量执行多条SQL语句的能力

这里我们先看一下我们的默认配置SimpleExecutor类,这里我们会通过我们的配置得到StatementHandler,然后通过这个StatementHandler来获取我们的Statement
在这里插入图片描述

这里我们发现其实和我们的JDBC是一样的,都是获取Connection,然后获取Statement,这里我们获取的Connection是我们通过动态代理增强之后的,具有有打印日志能力的Connection,我们在 MyBatis日志模板分析 中也是分析过的
在这里插入图片描述

我们继续看看它是如何获取Statement的,我们通过这个方法的实现类BaseStatementHandler,发现我们获取Statement的方法也是一个抽象方法,由其子类进行实现
在这里插入图片描述
在这里插入图片描述

因为我们在使用JDBC连接数据库的时候我们也是知道的,我们可以使用Statement,是不进行预编译的,或者我们使用PreparedStatemen,是使用预编译方式的。
在这里插入图片描述



看完了我们的SimpleExecutor类,这里我们再来看一看我们的ReuseExecutor类,这我们发现我们的doQuery执行的方法一模一样,它的主要区别就是在于获取Statement的过程之中
在这里插入图片描述

这里我们发现,他在创建Statement之前,会先拿到Sql语句,判断在它设置的缓存中是否有对应的Statement,有的话直接取出返回
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

要是在缓存中未找到的话,才会去创建一个Statement,并且会将其加入到缓存之中,这样下次就可以不用创建了。
在这里插入图片描述



还有一点就是我们在上述的 BaseExecutor 类的执行流程中发现,我们在在查询过程中,我们会拼接处CacheKey,然后去查一级缓存,没有查询到再去查询数据库,可是如果我们配置的二级缓存,在查询一级缓存前是会先查询二级缓存的,那么我们会在什么地方查询二级缓存呢


其实上,我们的 Executor 接口处理 BaseExecutor 实现类,还有另外一个 CachingExecutor 实现类
在这里插入图片描述


我们知道,我们MyBatis设置默认是开启二级缓存的,如果想要使用二级缓存,只需要在Mapper文件中,加上<cache> 节点即可,然后我们的Configuration文件在创建 Executor 就会创建对应的Executor类。
在这里插入图片描述

这里上述还判断了我们上述说了几个类型,我们在也是可以在MyBatis进行设置的,我们的 MyBatis配置 中的 setting 也有相关介绍
在这里插入图片描述


这里我们直接看 CacheExecutor 的 query 方法,发现它也是从我们的MappedStatement获取我们的Mapper中的SQL信息,还组装成了CacheKey,不过这里的CacheKey使用来查询二级缓存使用的
在这里插入图片描述

这里会先去下二级缓存,看看有没有设置二级缓存,如果有的话回去二级缓存中去数据,如果取不到数据的话,就是去调用我们的 BaseExecutor 类的 query 方法,接下来的步骤就和我们上述介绍的一致了。
在这里插入图片描述



最后我们总结下来,Executor类及其实现类的关系如下:
在这里插入图片描述 经过上述分析,我们发现Executor的实现类CachingExecutor,就是设置了二级缓存就查一下二级缓存,没有取到数据或者没有设置二级缓存的话,就交由BaseExecutor类进行处理,我们的BaseExecutor也没有干什么事,就是在查询操作中提供查询一级缓存的能力,在插入/更新等操作中提供事务的能里,然后操作数据库就交由它的几个子类中的其中某个进行处理。