说明

前面二看到了 sqlSession最终是找到MapperStatement然后委托给Executer执行的 Executer到底做了什么

接口定义

public interface Executor {
ResultHandler NO_RESULT_HANDLER = null; int update(MappedStatement var1, Object var2) throws SQLException; <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; CacheKey createCacheKey(MappedStatement var1, Object var2, RowBounds var3, BoundSql var4); boolean isCached(MappedStatement var1, CacheKey var2); 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各个实现

ClosedExecutor

org.apache.ibatis.executor.loader.ResultLoaderMap 中的一个内部静态类

 private static final class ClosedExecutor extends BaseExecutor {
public ClosedExecutor() {
super((Configuration)null, (Transaction)null);
} public boolean isClosed() {
return true;
} protected int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
throw new UnsupportedOperationException("Not supported.");
} protected List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
throw new UnsupportedOperationException("Not supported.");
} protected <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
throw new UnsupportedOperationException("Not supported.");
} protected <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException {
throw new UnsupportedOperationException("Not supported.");
}
}

没有具体实现  我们不会用到

简单SimpleExecutor

每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。(可以是Statement或PrepareStatement对象)

public class SimpleExecutor extends BaseExecutor {
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null; int var6;
try {
//获得configuration
Configuration configuration = ms.getConfiguration();
//根据configuration获得对应的StatementHandler 后面讲
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, (ResultHandler) null, (BoundSql) null);
stmt = this.prepareStatement(handler, ms.getStatementLog());
var6 = handler.update(stmt);
} finally {
//释放Statement
this.closeStatement(stmt);
} return var6;
}
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Connection connection = this.getConnection(statementLog);
Statement stmt = handler.prepare(connection, this.transaction.getTimeout());
handler.parameterize(stmt);
return stmt;
}
}

可以看到finally会关闭Statement

复用ReuseExecutor

Statement会根据sql语句进行保存 相同sql语句达到复用 避免多次编译

public class ReuseExecutor extends BaseExecutor {
//保存Statement key为sql语句
private final Map<String, Statement> statementMap = new HashMap(); public ReuseExecutor(Configuration configuration, Transaction transaction) {
super(configuration, transaction);
} public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, (ResultHandler)null, (BoundSql)null);
//构建Statemetn
Statement stmt = this.prepareStatement(handler, ms.getStatementLog());
return handler.update(stmt);
}
public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
Iterator i$ = this.statementMap.values().iterator(); while(i$.hasNext()) {
Statement stmt = (Statement)i$.next();
this.closeStatement(stmt);
}
//清空缓存
this.statementMap.clear();
return Collections.emptyList();
} private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
BoundSql boundSql = handler.getBoundSql();
//获得sql语句
String sql = boundSql.getSql();
Statement stmt;
//判断是否有缓存 如果有重缓存取
if (this.hasStatementFor(sql)) {
stmt = this.getStatement(sql);
this.applyTransactionTimeout(stmt);
} else {
Connection connection = this.getConnection(statementLog);
//如果没有创建Statement 并仿佛缓存
stmt = handler.prepare(connection, this.transaction.getTimeout());
this.putStatement(sql, stmt);
} handler.parameterize(stmt);
return stmt;
} private boolean hasStatementFor(String sql) {
try {
return this.statementMap.keySet().contains(sql) && !((Statement)this.statementMap.get(sql)).getConnection().isClosed();
} catch (SQLException var3) {
return false;
}
} private Statement getStatement(String s) {
return (Statement)this.statementMap.get(s);
} private void putStatement(String sql, Statement stmt) {
this.statementMap.put(sql, stmt);
}
}

Statement什么时候释放 doFlushStatements为父类的抽象方法 父类再rollback和commit 会调用doFlushStatements()(模板方法模式)

BaseExecutor代码

    public void commit(boolean required) throws SQLException {
if (this.closed) {
throw new ExecutorException("Cannot commit, transaction is already closed");
} else {
this.clearLocalCache();
//会里面会调用this.doFlushStatements()
this.flushStatements();
if (required) {
this.transaction.commit();
} }
}

批量BatchExecutor

public class BatchExecutor extends BaseExecutor {
public static final int BATCH_UPDATE_RETURN_VALUE = -2147482646;
private final List<Statement> statementList = new ArrayList();
private final List<BatchResult> batchResultList = new ArrayList();
//上一次sql
private String currentSql;
//上一次Statement
private MappedStatement currentStatement; public BatchExecutor(Configuration configuration, Transaction transaction) {
super(configuration, transaction);
} public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, RowBounds.DEFAULT, (ResultHandler)null, (BoundSql)null);
BoundSql boundSql = handler.getBoundSql();
String sql = boundSql.getSql();
Statement stmt;
//当前sql语句是否与上一次sql语句一样 如果一样同时 当前Statement是否与上一次Statement一样
if (sql.equals(this.currentSql) && ms.equals(this.currentStatement)) {
//取出最后一个Statement
int last = this.statementList.size() - 1;
stmt = (Statement)this.statementList.get(last);
this.applyTransactionTimeout(stmt);
handler.parameterize(stmt);
//获得BatchResult 增加参数inset table value('1111','2222',....)
BatchResult batchResult = (BatchResult)this.batchResultList.get(last);
batchResult.addParameterObject(parameterObject);
} else {
//不存在在则新增Statement
Connection connection = this.getConnection(ms.getStatementLog());
stmt = handler.prepare(connection, this.transaction.getTimeout());
handler.parameterize(stmt);
this.currentSql = sql;
this.currentStatement = ms;
this.statementList.add(stmt);
this.batchResultList.add(new BatchResult(ms, sql, parameterObject));
}
// 将sql以addBatch()的方式,添加到Statement中(该步骤由StatementHandler内部完成)
handler.batch(stmt);
return -2147482646;
} /**
* 负责批量执行
* @param isRollback
* @return
* @throws SQLException
*/
public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
boolean var17 = false; Statement stmt;
List var21;
Iterator i$;
label168: {
ArrayList var20;
try {
var17 = true;
ArrayList results = new ArrayList();
if (isRollback) {
var21 = Collections.emptyList();
var17 = false;
break label168;
} int i = 0; //批量执行
for(int n = this.statementList.size(); i < n; ++i) {
stmt = (Statement)this.statementList.get(i);
this.applyTransactionTimeout(stmt);
BatchResult batchResult = (BatchResult)this.batchResultList.get(i); try {
batchResult.setUpdateCounts(stmt.executeBatch());
MappedStatement ms = batchResult.getMappedStatement();
List<Object> parameterObjects = batchResult.getParameterObjects();
KeyGenerator keyGenerator = ms.getKeyGenerator();
if (Jdbc3KeyGenerator.class.equals(keyGenerator.getClass())) {
Jdbc3KeyGenerator jdbc3KeyGenerator = (Jdbc3KeyGenerator)keyGenerator;
jdbc3KeyGenerator.processBatch(ms, stmt, parameterObjects);
} else if (!NoKeyGenerator.class.equals(keyGenerator.getClass())) {
Iterator i$ = parameterObjects.iterator(); while(i$.hasNext()) {
Object parameter = i$.next();
keyGenerator.processAfter(this, ms, stmt, parameter);
}
}
} catch (BatchUpdateException var18) {
StringBuilder message = new StringBuilder();
message.append(batchResult.getMappedStatement().getId()).append(" (batch index #").append(i + 1).append(")").append(" failed.");
if (i > 0) {
message.append(" ").append(i).append(" prior sub executor(s) completed successfully, but will be rolled back.");
} throw new BatchExecutorException(message.toString(), var18, results, batchResult);
} results.add(batchResult);
} var20 = results;
var17 = false;
} finally {
if (var17) {
Iterator i$ = this.statementList.iterator(); while(i$.hasNext()) {
Statement stmt = (Statement)i$.next();
this.closeStatement(stmt);
} this.currentSql = null;
//释放
this.statementList.clear();
//释放
this.batchResultList.clear();
}
} i$ = this.statementList.iterator();
//释放
while(i$.hasNext()) {
stmt = (Statement)i$.next();
this.closeStatement(stmt);
} this.currentSql = null;
this.statementList.clear();
this.batchResultList.clear();
return var20;
} i$ = this.statementList.iterator(); while(i$.hasNext()) {
stmt = (Statement)i$.next();
this.closeStatement(stmt);
} this.currentSql = null;
this.statementList.clear();
this.batchResultList.clear();
return var21;
}
}

if (sql.equals(this.currentSql) && ms.equals(this.currentStatement))看出 如果sql一样同时是连续的 则是使用同一个statement
比如 aabb生成2个statement abba会生成三个statement  主要作用是减少sql预编译时间

缓存CachingExecutor

public class CachingExecutor implements Executor {
private Executor delegate;
public CachingExecutor(Executor delegate) {
this.delegate = delegate;
delegate.setExecutorWrapper(this);
} public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
BoundSql boundSql = ms.getBoundSql(parameterObject);
//根据sql和参数算出缓存key
CacheKey key = this.createCacheKey(ms, parameterObject, rowBounds, boundSql);
return this.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
} public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
//是否有缓存
Cache cache = ms.getCache();
if (cache != null) {
//是否清除缓存
this.flushCacheIfRequired(ms);
//是否应用缓存
if (ms.isUseCache() && resultHandler == null) {
//
this.ensureNoOutParams(ms, parameterObject, boundSql);
//如果缓存拿不到 则通过delegate重新执行query
List<E> list = (List)this.tcm.getObject(cache, key);
if (list == null) {
list = this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
this.tcm.putObject(cache, key, list);
} return list;
}
} return this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
} }

装饰者模式判断是否有缓存 如果没有则委托给delegate执行 拿到结果再将结果缓存

Executor的设置

默认为Simple

configuration配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="defaultExecutorType" value="REUSE" />
</settings>
</configuration>

openSession

@Override
public SqlSession openSession(ExecutorType execType, boolean autoCommit) {
return openSessionFromDataSource(execType, null, autoCommit);
}

mybatis源码阅读-执行器Executor(四)的更多相关文章

  1. mybatis源码阅读-执行器StatementHandle和ParameterHandler(五)

    StatementHandle 类图 各个实现类的作用 SimpleStatementHandler 用于使用Statement操作数据库(不会使用参数化查询?) PreparedStatementH ...

  2. Mina源码阅读笔记(四)—Mina的连接IoConnector2

    接着Mina源码阅读笔记(四)-Mina的连接IoConnector1,,我们继续: AbstractIoAcceptor: 001 package org.apache.mina.core.rewr ...

  3. mybatis源码-解析配置文件(四-1)之配置文件Mapper解析(cache)

    目录 1. 简介 2. 解析 3 StrictMap 3.1 区别HashMap:键必须为String 3.2 区别HashMap:多了成员变量 name 3.3 区别HashMap:key 的处理多 ...

  4. Mybatis源码阅读-配置文件及映射文件解析

    Mybatis源码分析: 1.配置文件解析: 1.1源码阅读入口: org.apache.ibatis.builder.xml.XMLConfigBuilder.parse(); 功能:解析全局配置文 ...

  5. Mybatis源码详解系列(四)--你不知道的Mybatis用法和细节

    简介 这是 Mybatis 系列博客的第四篇,我本来打算详细讲解 mybatis 的配置.映射器.动态 sql 等,但Mybatis官方中文文档对这部分内容的介绍已经足够详细了,有需要的可以直接参考. ...

  6. mybatis源码-解析配置文件(四)之配置文件Mapper解析

    在 mybatis源码-解析配置文件(三)之配置文件Configuration解析 中, 讲解了 Configuration 是如何解析的. 其中, mappers作为configuration节点的 ...

  7. Mybatis源码阅读 之 玩转Executor

    承接上篇博客, 本文探究MyBatis中的Executor, 如下图: 是Executor体系图 本片博客的目的就是探究如上图中从顶级接口Executor中拓展出来的各个子执行器的功能,以及进一步了解 ...

  8. mybatis源码阅读-Transaction和TransactionFactory(四)

    Transaction 类图 接口定义 public interface Transaction { Connection getConnection() throws SQLException; v ...

  9. mybatis源码阅读(动态代理)

    这一篇文章主要是记录Mybatis的动态代理学习成果,如果对源码感兴趣,可以看一下上篇文章  https://www.cnblogs.com/ChoviWu/p/10118051.html 阅读本篇的 ...

随机推荐

  1. Python三次登陆

    题目:Python实现三次登陆 不要急于马上把三次登陆写出来,一定要将复杂的程序简单化,必须一步一步地去扩展,这样才保证不会出错. 步骤一:实现简单的一次登陆 # 事先定义 user = 'dark_ ...

  2. hadoop-Combiner作用用法

    文章来源http://blog.csdn.net/ipolaris/article/details/8723782 reduce的输入每个key所对应的value将是一大串1,但处理的文本很多时,这一 ...

  3. 解决UTF-8方法归纳

    1:通过spring配置过滤器解决 <!-- 配置Spring提供的字符编码过滤器 --> <filter> <filter-name>SpringCharacte ...

  4. Web开发必须知道的知识点

    Web前端必须知道 一.常用那几种浏览器测试.有哪些内核(Layout Engine) 1.浏览器:IE,Chrome,FireFox,Safari,Opera. 2.内核:Trident,Gecko ...

  5. JavaScript--引用JS外部文件

    通过前面知识学习,我们知道使用<script>标签在HTML文件中添加JavaScript代码,如图: JavaScript代码只能写在HTML文件中吗?当然不是,我们可以把HTML文件和 ...

  6. hihocode 编程练习赛17

    1. f1 score 首先了解f1 score的计算方法, 我记得是学信息检索知道的, 然后简单处理就行. 由于我写的比较麻烦, 中间处理过程引入了一些除数为0的情况,导致错了很多次.其实是很简单的 ...

  7. python框架之Flask基础篇(四)-------- 其他操作

    1.蓝图 要用蓝图管理项目,需要导入的包是:from flask import Buleprint 具体大致分为三步: 1.先在子模块中导入蓝图包,然后再创建蓝图对象. 2.然后将子模块中的视图函数存 ...

  8. 二次封装OKHttp网络框架(1)

    1. 框架功能简介:暂时只有get.post两个请求 2. 请求的主要流程和区别: 2.1 get请求: (1)创建请求客户的 OkHttpClient对象 (2)创建请求构建器 Request.Bu ...

  9. PHP流程控制语句(if,foreach,break......)

    背景:PHP程序中,必不可少的要用到流程控制语句.这次对于流程控制语句进行一些总结. 条件控制语句和循环控制语句是两种基本的语法结构,它们都是用来控制程序执行流程.也是构成程序的主要语法基础. 一.程 ...

  10. (转)44 道 JavaScript 难题

    JavaScript Puzzlers原文 1. ["1", "2", "3"].map(parseInt)   答案:[1, NaN, N ...