MyBatis 四大组件之 Executor 执行器

数据库驱动连接管理和SQL解析的管理组件之 Executor 执行器

MyBatis 四大组件之 Executor 执行器

    每一个 SqlSession 都会拥有一个 Executor 对象,这个对象负责增删改查的具体操作,我们可以简单的将它理解为 JDBC中Statement 的封装版。

Executor的继承结构

如图所示,位于继承体系最顶层的是 Executor 执行器,它有两个实现类,分别是BaseExecutorCachingExecutor。

BaseExecutor是一个抽象类这种通过抽象的实现接口的方式是适配器设计模式之接口适配的体现,是 Executor 的默认实现,实现了大部分 Executor 接口定义的功能,降低了接口实现的难度。

BaseExecutor 的子类有三个,分别是SimpleExecutorReuseExecutorBatchExecutor

SimpleExecutor:简单执行器。是MyBatis的默认执行器,每执行一次update或select,就开启一个Statement对象,用完就直接关闭Statement对象(可以是Statement或者PreparedStatment 对象)

ReuseExecutor:可重用执行器,这里的重用是指重复使用Statement。它会在内部使用一个Map把创建的Statement都缓存起来,每次执行SQL命令时候都会去判断是否存在基于该SQL的Statement对象,如果存在Statement对象并且对应的Connection还没有关闭情况下就继续使用之前的Statement对象,并将其缓存起来。因为每次Sqlsession都有一个新的Executor对象,所以缓存在ReuseExecutor的Statement对象作用域是同一个Sqlsession.

BatchExecutor: 批处理执行器,用于将多个SQL一次性输出到数据库

CachingExecutor: 缓存执行器,先从缓存中查询结果,如果存在,就返回;如果不存在,再委托给 Executor delegate 去数据库中取,delegate 可以是上面任何一个执行器。

Executor的设计用现实做例子

Executor执行器是MyBatis的重要组件。

Executor相当于外包的Boss,它定义了甲方(SQL)需要干的活(Executor的主要方法),boss接到开发任务时候会先找到项目经理(CachingExecutor),项目经理几乎不懂技术,它主要和技术leader(BaseExecutor)打交道,技术leader主要负责框架搭建,具体工作都会交给下面的程序员来做。但程序员也有优劣,高级程序员(BatchExecutor)、中级程序员(ReuseExecutor)、初级程序员(SimpleExecutor),

它们干的活也不一样。一般有新的项目需求传达到项目经理这里,项目经理先判断自己手里有没有现成的类库或者项目直接套用(Cache),有的话就直接让技术leader拿来直接套用就好,没有的话就需要搭建框架,再把框架存入本地类库中,再进行解析。




Executor创建过程以及源码分析

直接使用MyBatis方式来分析。

创建完 SqlSessionFactory 之后,调用其openSession方法:

SqlSession sqlSession=factory.openSession();

SqlSessionFactory 的默认实现是 DefaultSqlSessionFactory,所以我们需要关心的就是 DefaultSqlSessionFactory 中的 openSession() 方法

openSession 调用的是openSessionFromDataSource方法,传递执行器的类型,方法传播级别,是否自动提交,然后在 openSessionFromDataSource 方法中会创建一个执行器


调用 newExecutor 方法,根据传入的 ExecutorType 类型来判断是哪种执行器,然后执行相应的逻辑


ExecutorType 的选择:

ExecutorType 来决定 Configuration 对象创建何种类型的执行器,它的赋值可以通过两个地方进行赋值:

可以通过 settings 标签来设置当前工程中所有的 SqlSession 对象使用默认的 Executor

<settings><!--取值范围 SIMPLE,REUSE,BATCH--><setting name="defaultExecutorType"value="SIMPLE"/></settings>

另外一种直接通过Java对方法赋值的方式

session=factory.openSession(ExecutorType.BATCH);

ExecutorType 是一个枚举,它只有三个值 SIMPLE, REUSE, BATCH

创建完成 Executor 之后,会把 Executor 执行器放入一个 DefaultSqlSession 对象中来对四个属性进行赋值,他们分别是configuration、executor、dirty、autoCommit

Executor接口的主要方法

增、更、删 :

int update(MappedStatement var1, Object var2)throws SQLException;

查询,带分页,带缓存,BoundSql :

<E>  List<E> query(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4, CacheKey var5, BoundSql var6)throws SQLException;

  查询,带分页:

<E> List <E> query(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4)throws SQLException;

通过游标查询(数据量大时候用):

<E> Cursor<E> queryCursor(MappedStatement var1, Object var2, RowBounds var3)throws SQLException;

刷新批处理语句:

List<BatchResult> flushStatements()throws SQLException;

提交:

void commit(boolean var1)throws SQLException;

回滚:

void rollback(boolean var1)throws SQLException;

创建缓存KEY:

CacheKey createCacheKey(MappedStatement var1, Object var2, RowBounds var3, BoundSql var4);

判断是否缓存了:

boolean isCached(MappedStatement var1, CacheKey var2);

清除session缓存:

void clearLocalCache();

延迟加载:

void deferLoad(MappedStatement var1, MetaObject var2, String var3, CacheKey var4, Class var5);

Transaction getTransaction();

void close(boolean var1);

boolean isClosed();

void setExecutorWrapper(Executor var1);


Executor 接口的方法还是比较多的,这里我们就几个主要的方法和调用流程来做一个简单的描述


缓存机制角度:



从查询query方法角度解剖:

query 方法有两种形式,一种是直接查询;一种是从缓存中查询,下面来看一下源码以及时序图:

当有一个查询请求访问的时候,首先会经过 Executor 的实现类 CachingExecutor,先从缓存中查询 SQL 是否是第一次执行,如果是第一次执行的话,那么就直接执行 SQL 语句,并创建缓存,如果第二次访问相同的 SQL 语句的话,那么就会直接从缓存中提取

CachingExecutor:

// 第一次查询,并创建缓存


MapperStatement维护了一条 select、update、delete、insert 节点的封装,包括资源(resource),配置(configuration),SqlSource(sql源文件)等。使用Configuration 的 getMappedStatement 方法来获取 MappedStatement 对象。

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

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


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

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

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

Executor的执行查询的大致流程时序图:


update() 方法(update 链是insert、update、delete 在语义上其实都是更新的意思)

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

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

update时序图:

queryCursor()方法

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

// 查询可以返回Cursor<T>类型的数据,类似于JDBC里的ResultSet类,

// 当查询百万级的数据的时候,使用游标可以节省内存的消耗,不需要一次性取出所有数据,可以进行逐条处理或逐条取出部分批量处理。

public  interfaceCursor<T>extendsCloseable,Iterable<T>   {

booleanisOpen();

booleanisConsumed();

intgetCurrentIndex();

}

flushStatements() 方法

主要用来释放 statement,或者用于 ReuseExecutor 和 BatchExecutor 来刷新缓存。

createCacheKey() 方法

createCacheKey() 方法主要由 BaseExecutor 来执行并创建缓存,MyBatis 中的缓存分为一级缓存和二级缓存

Executor 中的其他方法

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 225,015评论 6 522
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 96,373评论 3 404
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 172,253评论 0 368
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 61,069评论 1 300
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 70,079评论 6 400
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,550评论 1 314
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,911评论 3 429
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 40,892评论 0 279
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,435评论 1 324
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,465评论 3 346
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,586评论 1 355
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,178评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,920评论 3 340
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,356评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,493评论 1 277
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 50,151评论 3 381
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,663评论 2 366

推荐阅读更多精彩内容