引言

执行器其名Executor,它是MyBtis中一个核心组件,地位非常高,有多高?如果硬要把MyBatis核心组件排个位话,它就是老大。所以开篇就要先介绍它。

这个老大它做了什么?其它的组件又是指什么?接下来,通过一个SQL执行过程,一一为你们介绍。

背景

一条SQL的执行,最基本的组件是什么?先来看两行代码,这两行代码就完成了一次SQL查询。

  • 第一行:创建一个执行器。
  • 第二行:传入查询条件并执行。
1 Executor executor =configuration.newExecutor(jdbcTransaction);
2 executor.query(ms, 10, DEFAULT,NO_RESULT_HANDLER);
3 /**
4  * 参数说明:
5  * 1.sql映射
6  * 2.参数值
7  * 3.默认分页
8  * 4.默认结果集处理
9  */

简单两行代码就完成了一次SQL查询,这和我们平常所认识的MyBatis不一样,通常要么是通过Mappr接口、要么通过SqlSession来执行。但通过这个例子可以证实,在一个基本的SQL流程当中这两个对象都不是必须的。

哪些才是必须的呢?就下面这四个组件:

SQL执行必备四大组件包括:

  1. 执行器:Executor, 处理流程的头部,主要负责缓存、事务、批处理。一个执行可用于执行多条SQL。它和SQL处理器是1对N的关系。
  2. Sql处理器:StatementHandler 用于和JDBC打道,比如基于SQL声明Statement、设置参数、然后就是调用Statement来执行。它只能用于一次SQL的执行
  3. 参数处理器:ParameterHandler,用于解析SQL参数,并基于参数映射,填充至PrepareStatement。同样它只能用于一次SQL的执行
  4. 结果集处理器:ResultSetHandler,用于读取ResultSet 结果集,并基于结果集映射,封装成JAVA对象。他也只用用于一次SQL的执行。

一次SQL执行指:执行器中每调用一次query或update,都会生成新实例。

这四个组件组成了MyBatis核心流程,接下来的章节就是针对对它们的学习,涉及的内容非常多。这里我们只要知道Executor在这里是领头的存在。所以我们先聚焦学习执行器。

功能与职责

在MyBatis 3.5.1版本中,Executor接口总共有15个方法,可以分成执行、事务、缓存三类。

分类 方法名称 描述
执行 update 更新
query 查询
query 重载的查询方法(可指定SQL和缓存key)
queryCursor 查询游标
flushStatements 批处理更新(只能用于update)
事务 commit 提交
rollback 回滚
close 关闭执行器
isClosed 执行器是否关闭
缓存 createCacheKey 创建缓存Key
isCached 指定SQL执行是否能命中缓存
clearLocalCache 清空一级缓存
deferLoad 延迟加载缓存(用于子查询引用)

缓存,在这里全部指MyBatis一级缓存,不涉及二级缓存。

现在我们知道了,执行的主要职责是执行、事务与缓存。另外我们可以发现一个规律,就是除了基本的更新与查询方法之外。基它的都是针对多个SQL执行的管理 。比如说事务就是针对多个SQL的提交、回滚。缓存也是一样的、如果只执行一个SQL,缓存将变得毫无意义,因为永远也命中不了。(这里指一级缓存)。

实现

执行器的实现有三种:

  1. SimpleExecute 简单执行器(默认)
  2. ReuseExecute 可重用执行器
  3. BatchExecute 批处理执行器

简单执行器

SimpleExecutor是执行器的默认实现,主要完成了“执行”功能,在利用StatementHandler 完成。每次调用执行方法 都会构建一个StatementHandler,并预行参数,然后执行。

1 SimpleExecutor executor =
2 new SimpleExecutor(configuration, jdbcTransaction);
3 List<Object> list = executor.doQuery(ms, 10, RowBounds.DEFAULT, SimpleExecutor.
4 NO_RESULT_HANDLER, ms.getBoundSql(10));

执行指queryupdatequeryCursor 方法

可重用执行器

ReuseExecutor可重用执行器的特点是,可重复使用JDBC中Statement。该执行器在执行SQL时会把Statement缓存起来,如果下次碰到相同的SQL,就会取出来使用。

批处理执行器

BatchExecutor 批处理执行器,每次的执行操作 不会立即执行,而是把对应的Statement 填充好参数之后暂存起来。当调用 flushStatements 的时候一次性提交到数据库。它可用于批处理插入的场景。效果等同于SQL语句的拼装。

另外BatchExecutor 也会利用Jdbc Statement 中的batch功能。把多个连续且相同的SQL语句,添加到一个Statement中去。然后用executeBatch方法去执行。

注意:在重复利用Statement时 ReuseExecutor 只要SQL相同就可以共用。但在BatchExecutor 时除了相同还必须是连续的。这个连续的原因是什么呢?

原因是为保证批处理的执行顺序,必须与调用方执行SQL顺序相同。如图中1和4是相同的Update语句,假如4合并到1,其就会先于2、3执行。这显然是会出问题的。假如4用来修改3新增的记录,它就修改不了。

示例:

1 BatchExecutor executor = new BatchExecutor(configuration, jdbcTransaction);
2 MappedStatement ms = configuration.getMappedStatement("org.coderead.mybatis.UserMapper.setName");
3 MappedStatement addMapper = configuration.getMappedStatement("org.coderead.mybatis.UserMapper.addUser");
4 Map map=new HashMap<>();
5 map.put("id",10);
6 map.put("name","鲁班大佬");
7 //1.执行修改
8 executor.doUpdate(ms,map);
9 //2.新增
10 executor.doUpdate(addMapper,Mock.newUser());
11 User newUSer = Mock.newUser();
12 newUSer.setId(9999);
13 //3.新增
14 executor.doUpdate(addMapper, newUSer);
15 map.put("id",newUSer.getId());
16 //4.执行修改
17 executor.doUpdate(ms,map);
18 List<BatchResult> batchResults = executor.flushStatements();// 刷新
19 System.out.println(batchResults.size()); //读取结果

在上面的示例中,最终会打印出结果3个,因为2和3合并了一个Statement,而1和4并没有。

基础执行器

执行器的职责包括:执行、事务、缓存。前面所提的三种执行器,都是只针针对执行的,并未涉及事务与缓存,这部分操作因为都是共性操作,所以其逻辑被抽像到基础执行器了。

BaseExecutor(基础执行器)是一个抽象类。三种执行器都是继承自它,并实现它的 doQuery与doUpdate方法,用于具体的执行。

一级缓存

执行器的使用都是从query与update和方法进入,然后BaseExecute 在其中加入一级缓存逻辑,如:创建缓存Key,获取缓存、清空缓存、填充缓存等。只有缓存未命中的情况下才会调用抽像方法doQuery查询数据库。

通过一个示例来了解一下一级缓存的命中。

1 Executor executor = new SimpleExecutor(configuration, jdbcTransaction);
2 Object result1 = executor.query(ms, 10, DEFAULT, NO_RESULT_HANDLER);
3 Object result2 = executor.query(ms, 10, DEFAULT, NO_RESULT_HANDLER);
4 System.out.println(result1==result2);

上述例子中将打印 true,因为第一次查询会填充缓存,而第二次查询将会命中缓存。

注:关于一级缓存细节后续章节会详细介绍

事务

关于事务基础执行器提供了,commit与rollback方法。这里面的逻辑除了常规JDBC提交回滚外,还包括缓存的清空与批处理的提交与回滚操作。

注:在与Spring 集成之后,事务操作都交收Spring 实现,而不在使用MyBatis来管理事务。

会话与执行器

一般开发, 我们不会直接使用执行器,而是通过会话来使用。其结构如下图:

在会话中会包含一个唯一的执行器,并且一个执行器,只能被一个会话使用,二者是1对1的关系 。在开启会话时, 可通过传递ExecutorType 参数来指定具体的执行器类型。其值有SIMPLE, REUSE, BATCH三种,分别对应前面所说的三种执行器。

也可以通过修改defaultExecutorType设置来修改默认的执行器

1 <setting name="defaultExecutorType" value="SIMPLE|REUSE|BATCH"/>

通常我们会把defaultExecutorType设置成REUSE

所以一个完整的执行过程就是SqlSession、BaseExecutor、SimpleExecutor或其它实现。

二级缓存与执行器

CacheExecutor是二级缓存执行器,里面包含了二级缓存的逻辑。这里面的设计用到了装饰器模式,对一个执行器进行装饰,从而嵌入二级缓存功能。如下例代码所示:

1 Executor delegate = new SimpleExecutor(configuration, jdbcTransaction);
2 CachingExecutor executor = new CachingExecutor(delegate);
3 Object result=executor.query(ms, 10, DEFAULT, NO_RESULT_HANDLER);

代码中delegate是一个简单执行器,它被CachingExecutor所装饰。当调用query方法时先检查有没有命中二级缓存,如果没有在交给delegate继续完成查询逻辑。

在默认情况下二级缓存是开启的,可通过以下参数关闭:

1 <setting name="cacheEnabled" value="true"/>

如果没有关闭,在开启的情况下,整个执行器的结构如下图:

执行器的构建

执行器的构建在打开会话时,基于Configuration中的newExecutor方法实现。主要逻辑是:

  1. 基于指定类型创建具体执行器
  2. 创建缓存执行器,用于装饰执行器 (如果开启缓存)
  3. 使用插件对缓存执行器进行包装。(如果配置了插件)

最终结构有可能被包装了三次,结构如下图:

注:关于插件,后续章节 会在详细介绍,这里大家先 知道 它和执行器的关系 即可。

总结:

  1. 执行器有三种实现分别是,简单、重用、批处理执行器
  2. 三种执行之上是基础执行器,用于实现一级缓存与事务的功能
  3. 执行器与会话关系是1比1的关系,每个会话都对一个唯一的执行器
  4. 缓存执行器采用了装饰者设计模式,从而嵌入了二级缓存功能

jdbc preparestatement 执行多条语句_MyBatis执行器相关推荐

  1. jdbc preparestatement 执行多条语句_第二十一天JDBC编程

    JDBC编程 JDBC是连接数据库和Java程序的桥梁,通过JDBC API可以方便地实现对各种主流数据库的操作.本篇将介绍一下如何使用JDBC操作数据库(以MySQL为例). 一.JDBC JDBC ...

  2. jdbc preparestatement 执行多条语句_jmeter获取JDBC响应做接口关联(三)

    概述: jmeter中,常常需要连接数据库去断言业务是否正确.因此jdbc数据库关联是必须掌握的核心知识. 基础操作 JDBC请求,最核心的是两个jar包: mysql驱动-mysql-connect ...

  3. MyBatis 同时执行多条语句【简单扼要】

    目的:MyBatis 同时执行多条语句 第一步:打开一个约束   allowMultiQueries=true url: jdbc:mysql://127.0.0.1:3306/tourism?use ...

  4. jdbc 批量执行sql

    最近有个需求是需要在java 后端执行导入,数据量比较大, 需要对数据进行很多操作,最后要执行插入数据操作, 一开始先组织好插入数据的sql语句放在数组中,使用的是 jdbcTemplate.batc ...

  5. JDBC连接执行MySQL存储过程报空指针或权限错误

    最近使用root用户编写了几个存储过程,但是使用普通用户通过JDBC连接执行却报错: java.lang.NullPointerException...... 或 java.sql.SQLExcept ...

  6. oracle execute immediate执行多条语句_用数据库的方式思考SQL是如何执行的

    私信我或关注微信号:猿来如此呀,回复:学习,获取免费学习资源包. 今天我们就从数据库的角度来思考一下 SQL 是如何被执行的. 关于今天的内容,你会从以下几个方面进行学习: Oracle 中的 SQL ...

  7. Mysql 一次性执行多条语句的实现

    1.mysql数据库默认情况下,mysql_query()是一次只执行一条语句. #include "stdafx.h" #include <mysql.h> #inc ...

  8. mysql:通过JDBC接口执行创建触发器的SQL语句

    delimiter 以下是从mysql官方文档<23.3.1 Trigger Syntax and Examples>抄来的一段创建触发器的SQL脚本, delimiter // CREA ...

  9. Java数据库JDBC——prepareStatement的用法和解释

    转自:http://blog.csdn.net/QH_JAVA/article/details/48245945 一.prepareStatement 的用法和解释 1.PreparedStateme ...

最新文章

  1. ubuntu编译安装php5 mysql nginx
  2. 场景/故事/story——寻物者发布消息场景、寻失主发布消息场景、消息展示场景、登录网站场景...
  3. 机器学习 综合评价_PyCaret:机器学习综合
  4. maven 多仓库和镜像设置
  5. hive-jdbc/odbc的解读和看法
  6. leetcode 21 java_LeetCode 21. 合并两个有序链表
  7. 双系统下卸载linux系统
  8. 世界哲学日2600年西方哲学思想发展史谱系图和哲学50命题(公号回复“西方哲学”下载PDF彩标典藏版,欢迎转发、赞赏、支持科教)
  9. Glide加载长图;WebView加载富文本(图片自适应屏幕大小)
  10. Google 2018 更新内容
  11. 传智黑马java基础学习——day10(继承、抽象类)
  12. openpyxl不能读取xls格式
  13. 瞧瞧我们对漫画图片都做了什么!?
  14. 京东和区块链的那些事儿
  15. 加勒比海盗船-最优装载问题(2021/1/16)
  16. 随机切换必应美图html代码,随机显示必应每日一张图片为背景网站技巧教程
  17. 大数据开发:MongoDB系统架构简介
  18. No module named ‘google.rpc‘ 报错解决
  19. 手机数据恢复软件怎么选择
  20. UA OPTI501 电磁波6 麦克斯韦方程组及其不同形式

热门文章

  1. HDU1256 画8【打印图案】
  2. Bailian2701 Bailian3864 POJ NOI0105-39 与7无关的数【进制】
  3. I00016 打印等腰三角形字符图案(底边在左或右)
  4. Java —— 正则表达式
  5. fatal error: caffe/proto/caffe.pb.h: No such file or directory
  6. 多道编程与多用户环境
  7. C/C++ —— 算符优先级的问题
  8. C 标准库—— string.h
  9. VS 2013 统一修改所有工程的目录配置(以 boost、opencv3 的安装为例)
  10. html怎么添加背景图片_万能的产品介绍PPT页面是怎么炼成的?