1.Executor介绍:

Executor是mybatis的核心接口之一,其中定义了数据库操作的基本方法,它的子类结构图如下:这这张关系图中,涉及到了模板方法模式和装饰器模式。BaseExecutor是一个抽象父类,定义了一级缓存和事务相关的公共的固定不变的方法,同时定义了doUpdate,doQuery等抽象方法,这些抽象方法是在BaseExecutor的四个子类中实现的。这里用到了模板方法模式。对于CachingExecutor这个类,它为Executor提供了二级缓存的功能,它是一个装饰类,被装饰的目标类是BaseExecutor的四个子类,比如是SimpleExecutor,所以这里用到了装饰器模式。

2.源码分析:

2.1 Executor源码:

public interface Executor {

  ResultHandler NO_RESULT_HANDLER = null;
// 执行update,insert,delete三种类型的SQL
int update(MappedStatement ms, Object parameter) throws SQLException;
// 执行select类型的SQL
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException; <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;

// 批量执行SQL
List<BatchResult> flushStatements() throws SQLException;
// 事务提交
void commit(boolean required) throws SQLException;
// 事务回滚
void rollback(boolean required) throws SQLException;
// 创建一级缓存中使用到的CacheKey对象
CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql); boolean isCached(MappedStatement ms, CacheKey key);
// 清空一级缓存
void clearLocalCache(); void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);
// 获取事务对象
Transaction getTransaction(); void close(boolean forceRollback); boolean isClosed(); void setExecutorWrapper(Executor executor); }

2.2 BaseExecutor

BaseExecutor是一个实现了Executor的抽象类,它实现了Executor的大部分方法,比如:一级缓存管理和事务管理的基本功能,它的四个子类只需要实现doQuery,doUpdate等抽象方法来完成数据库的相关操作。

public abstract class BaseExecutor implements Executor {

  private static final Log log = LogFactory.getLog(BaseExecutor.class);

  protected Transaction transaction;  // transaction对象
protected Executor wrapper; // 封装的executor对象 protected ConcurrentLinkedQueue<DeferredLoad> deferredLoads;
protected PerpetualCache localCache; // 一级缓存 用于缓存该Executor对象查询结果集映射得到的结果对象
protected PerpetualCache localOutputParameterCache;
protected Configuration configuration; protected int queryStack = 0;
private boolean closed;

// 获取transaction对象
public Transaction getTransaction() {
if (closed) throw new ExecutorException("Executor was closed.");
return transaction;
} 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);
}

// 批量执行多条缓存的SQL
public List<BatchResult> flushStatements(boolean isRollBack) throws SQLException {
if (closed) throw new ExecutorException("Executor was closed.");
return doFlushStatements(isRollBack);
} public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
BoundSql boundSql = ms.getBoundSql(parameter);
CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}

// 先查询一级缓存,如果未命中,则再查询数据库
@SuppressWarnings("unchecked")
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
if (closed) throw new ExecutorException("Executor was closed.");
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
List<E> list;
try {
queryStack++;
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) {
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
// 此处会调用在子类中实现的doQuery方法,默认的子类是SimpleExecutor
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
queryStack--;
}
if (queryStack == 0) {
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
deferredLoads.clear(); // issue #601
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
clearLocalCache(); // issue #482
}
}
return list;
} // 事务提交
public void commit(boolean required) throws SQLException {
if (closed) throw new ExecutorException("Cannot commit, transaction is already closed");
clearLocalCache();
flushStatements();
if (required) {
transaction.commit();
}
}

// 事务回滚
public void rollback(boolean required) throws SQLException {
if (!closed) {
try {
clearLocalCache();
flushStatements(true);
} finally {
if (required) {
transaction.rollback();
}
}
}
}

// 需要在子类中实现的update操作
protected abstract int doUpdate(MappedStatement ms, Object parameter)
throws SQLException; protected abstract List<BatchResult> doFlushStatements(boolean isRollback)
throws SQLException;

// 需要在子类中实现的query操作
protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
throws SQLException;
} }

由上面的query方法可知,BaseExecutor提供了一级缓存的查询功能,如果一级缓存未命中,则再会调用在它的子类中实现的doQuery方法,默认的子类是SimpleExecutor。

2.3 SimpleExecutor

SimpleExecutor继承了BaseExecutor抽象类,它是最简单的Executor接口的实现。这里使用到了模板方法模式,一级缓存和事务管理等固定不变的操作封装到了BaseExecutor这个父类中,而update,query等与数据库交互的基本方法,都在子类中实现的。

public class SimpleExecutor extends BaseExecutor {

  public SimpleExecutor(Configuration configuration, Transaction transaction) {
super(configuration, transaction);
}
// upate,insert,delete操作
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);
}
}
// query操作
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对象
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
// 完成Statement的创建和初始化
stmt = prepareStatement(handler, ms.getStatementLog());
// 调用StatementHandler.query方法,执行SQL语句,并通过ResultSetHandler完成结果集的映射
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
} }

对于另外三个子类这里就不做分析了。接下来介绍CachingExecutor这个类

2.4 CachingExecutor

对于CachingExecutor,通过装饰器模式,为Executor增加了二级缓存的功能,接下来就对它的属性和主要方法做个分析:

2.4.1 属性:

  private Executor delegate; // 被装饰的类,也成为目标类
private TransactionalCacheManager tcm = new TransactionalCacheManager(); // 用于管理Cahce和TransactionCache,也就是和二级缓存相关的

2.4.2 查询方法:

  public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
Cache cache = ms.getCache();
// 如果映射配置文件中配置了<cache/>,则此处cache!= null
if (cache != null) {
flushCacheIfRequired(ms);
// 查询节点的useCache配置以及是否是否使用了resultHandler
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, parameterObject, boundSql);
@SuppressWarnings("unchecked")
// 查询二级缓存
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
// 如果二级缓存没有查询出结果,会调用封装的Executor对象的query方法,其中会先查询一级缓存,再执行数据库查询操作
list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578. Query must be not synchronized to prevent deadlocks
}
return list;
}
}
// 没有启动二级缓存,直接调用底层Executor执行数据库的查询操作
return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

 2.4.3 事务提交:

  public void commit(boolean required) throws SQLException {
delegate.commit(required); // 调用底层的Executor提交事务
tcm.commit(); // 遍历所有的TransactionCahce对象执行commit方法
}

关于Executor就暂时说这么多吧,其实这些内容在其他文章中都有提到,这里不过是做一个简单的分类总结。

Executor介绍的更多相关文章

  1. java并发框架Executor介绍

    Executor框架是指java 5中引入的一系列并发库中与executor相关的一些功能类,其中包括线程池,Executor,Executors,ExecutorService,Completion ...

  2. MyBatis学习笔记(二) Executor

    一.概述 当我们打开一个SqlSession的时候,我们就完成了操作数据库的第一步,那MyBatis是如何执行Sql的呢?其实MyBatis的增删改查都是通过Executor执行的,Executor和 ...

  3. Executor线程池的简单使用

    我们都知道创建一个线程可以继承Thread类或者实现Runnable接口,实际Thread类就是实现了Runnable接口. 到今天才明白后端线程的作用:我们可以开启线程去执行一些比较耗时的操作,类似 ...

  4. 跟着阿里p7一起学java高并发 - 第19天:JUC中的Executor框架详解1,全面掌握java并发核心技术

    这是java高并发系列第19篇文章. 本文主要内容 介绍Executor框架相关内容 介绍Executor 介绍ExecutorService 介绍线程池ThreadPoolExecutor及案例 介 ...

  5. mybatis源码分析(五)------------SQL的执行过程

    在对SQL的执行过程进行分析前,先看下测试demo: /** * @author chenyk * @date 2018年8月20日 */ public class GoodsDaoTest { pr ...

  6. Java Executor并发框架(一)整体介绍

    一.概述 Java是天生就支持并发的语言,支持并发意味着多线程,线程的频繁创建在高并发及大数据量是非常消耗资源的,因为java提供了线程池.在jdk1.5以前的版本中,线程池的使用是及其简陋的,但是在 ...

  7. Java 并发专题 : Executor详细介绍 打造基于Executor的Web服务器

    转载标明出处:http://blog.csdn.net/lmj623565791/article/details/26938985 继续并发,貌似并发的文章很少有人看啊~哈~ 今天准备详细介绍java ...

  8. Java 并发专题 : Executor具体介绍 打造基于Executor的Webserver

    转载标明出处:http://blog.csdn.net/lmj623565791/article/details/26938985 继续并发,貌似并发的文章非常少有人看啊~哈~ 今天准备具体介绍jav ...

  9. Executor框架(一)Executor框架介绍

    Executor框架简介 Executor框架的两级调度模型   在HotSpot VM的线程模型中,Java线程被一对一映射为本地操作系统线程.Java线程启动时会创建一个本地操作系统线程:当Jav ...

随机推荐

  1. go基础之数组和切片

    数组 数组的定义: 数组是具有固定长度并拥有零个或者多个相同数据类型元素的序列 定义一个数组的方法:var 变量名[len] type 例子:var a[5] int //3个整数的数组var a[5 ...

  2. Git 遇到的坑

    ssh出错 gitlab服务器添加完公钥之后,ssh服务器然后报了这个错误 sign_and_send_pubkey: signing failed: agent refused operation ...

  3. BZOJ1095:[ZJOI2007]Hide 捉迷藏(动态点分治)

    Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩 捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条 ...

  4. 关于box-shadow和drop-shadow的显著区别

    一.box-shadow box-shadow是css3中新增的属性,用于增加边框阴影,让原有的元素变得更多样性,它名下有四位小弟,老大控制水平方向偏移,老二控制垂直方向偏移,老三控制模糊度,最小的老 ...

  5. memcache讲解和在.net中初使用

    memcache讲解和在.net中初使用 2017年10月17日 22:51:36 等待临界 阅读数:503   前言 传统数据库面临的问题 数据库死锁 磁盘IO 正文 了解memcache 原理 基 ...

  6. PostgreSQL安装和使用

    青岛OJ系统用的关系型数据库是PostgreSQL,为此对PostgreSQL大致了解下. 今天的主要话题围绕下面两个方面: PostgreSQL安装 PostgreSQL使用 一.PostgreSQ ...

  7. GitHub存储库泄露了API令牌和加密密钥

    导读 北卡罗莱纳州立大学(NCSU)学者的一项研究表明,一些GitHub存储库泄漏API令牌和密码密钥.研究人员分析了分布在数百万存储库中的10亿多个GitHub文件.研究人员使用GitHub搜索AP ...

  8. 【Atcoder hbpc C 183】1=0.999...

    Atcoder hbpc C 题意:给n个循环小数或者有限小数,问其中有多少个互不相同的. 思路:我的思路比较繁琐. 首先我们考虑分数化小数:假设原来的数是\(a.b(c)\),那么这个分数就是\(a ...

  9. Hive学习之路 (一)Hive初识

    Hive 简介 什么是Hive 1.Hive 由 Facebook 实现并开源 2.是基于 Hadoop 的一个数据仓库工具 3.可以将结构化的数据映射为一张数据库表 4.并提供 HQL(Hive S ...

  10. CF434D Nanami's Power Plant 最小割

    传送门 因为连距离限制的边的细节调了贼久QAQ 这个题和HNOI2013 切糕性质相同,都是有距离限制的最小割问题 对于每一个函数,用一条链记录变量\(x\)在不同取值下这个函数的贡献.对于一个\(x ...