MYBATIS执行器模块
执行器模块
Executor是MyBaits核心接口之一,定义了数据库操作最基本的方法,SqlSession的功能都是基于它来实现的
什么是执行器
什么是执行器?Mybatis中所有的Mapper语句的执行都是通过Executor进行的,Executor是Mybatis的一个核心接口,其定义如下。从其定义的接口方法我们可以看出,对应的增删改语句是通过Executor接口的update方法进行的,查询是通过query方法进行的。虽然Executor接口的实现类有BaseExecutor和CachingExecutor,而BaseExecutor的子类又有SimpleExecutor、ReuseExecutor和BatchExecutor,但BaseExecutor是一个抽象类,其只实现了一些公共的封装,而把真正的核心实现都通过方法抽象出来给子类实现,如doUpdate()、doQuery();CachingExecutor只是在Executor的基础上加入了缓存的功能,底层还是通过Executor调用的,所以真正有作用的Executor只有SimpleExecutor、ReuseExecutor和BatchExecutor。它们都是自己实现的Executor核心功能,没有借助任何其它的Executor实现,它们是实现不同也就注定了它们的功能也是不一样的。Executor是跟SqlSession绑定在一起的,每一个SqlSession都拥有一个新的Executor对象,由Configuration创建。
大致流程
Executor中的大部分方法的调用链其实是差不多的,下面都是深入源码分析执行过程,如果你没有时间或者暂时不想深入研究的话,给你下面的执行流程图作为参考
Executor接口
Executor接口是SQL执行器的核心,所有的sql操作都是通过Executor接口来完成的,底层有各种的实现
1 | /** |
CachingExecutor类
缓存执行器相对于其他执行器的差别在于,首先是在query()方法中判断是否使用二级缓存(也就是mapper级别的缓存)。虽然mybatis默认启用了CachingExecutor,但是如果在mapper层面没有明确设置二级缓存的话,就退化为SimpleExecutor了。二级缓存的维护由TransactionalCache(事务化缓存)负责,当在TransactionalCacheManager(事务化缓存管理器)中调用putObject和removeObject方法的时候并不是马上就把对象存放到缓存或者从缓存中删除,而是先把这个对象放到entriesToAddOnCommit和entriesToRemoveOnCommit这两个HashMap之中的一个里,然后当执行commit/rollback方法时再真正地把对象存放到缓存或者从缓存中删除,具体可以参见TransactionalCache.commit/rollback方法。
这个Executor执行类是使用内存的,将数据保存到缓存中,这样可以有效的解决增删改查性能。缓存的作用域为mapper(namespace),所以同一个namespace的操作会影响到相同作用域下的缓存,这样不同的域对同一个表进行操作很有可能导致缓存中的数据不一样,出现问题,还是不推荐使用。
1 | /** |
BaseExecutor类
它是一个实现了Executor接口的抽象类,实现了接口中的大部分方法,其中就是使用了模板模式,它主要提供了缓存和事物管理的基本功能,不同的实现类,只要实现4个基本方法来完成数据库的相关操作,这4个抽象方法:
- doUpdate()
- doQuery()
- doFlushStatement()
- doQueryCursor。
1 | <settings> |
配置之后在Configuration类中的newExecutor()函数会选择具体使用的子类,实现如下:
1 | /** |
结构信息
1 | /** |
查询相关
先从缓存中查询,不存在然后再从物理数据库中查询
1 | /** |
数据库中查询数据
从数据库中查询数据最终调用的是抽象方法doQuery
1 | /** |
更新方法
查询,删除,更新最终都是调用的update方法,然后调用doUpdate抽象方法
1 | /** |
缓存相关
MyBatis 对于其 Key 的生成采取规则为:[mappedStementId + offset + limit + SQL + queryParams + environment]生成一个哈希码
1 | /** |
事务相关
1 | /** |
SimpleExecutor类
SimpleExecutor通过类名可以看出,它是一个简单的执行类,并不会做一些处理就执行sql
1 | /** |
BatchExecutor类
通过批量操作来提高性能
1 | /** |
ReuseExecutor类
ReuseExecutor,顾名思义,是可以重用的Executor。它重用的是Statement对象,它会在内部利用一个Map把创建的Statement都缓存起来,每次在执行一条SQL语句时,它都会去判断之前是否存在基于该SQL缓存的Statement对象,存在而且之前缓存的Statement对象对应的Connection还没有关闭的时候就继续用之前的Statement对象,否则将创建一个新的Statement对象,并将其缓存起来。因为每一个新的SqlSession都有一个新的Executor对象,所以我们缓存在ReuseExecutor上的Statement的作用域是同一个SqlSession
1 | /** |