说明

前面二看到了 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. IDEA Spark Streaming Kafka数据源-Consumer

    import org.apache.spark.SparkConf import org.apache.spark.streaming.kafka.KafkaUtils import org.apac ...

  2. django入门与实践 3-1 环境搭建

    Python 2.7 .Django对2.7.3.5.3.4都是支持的. https://www.djangoproject.com/download/ django对python的兼容情况 pip安 ...

  3. bzoj1121[POI2008]激光发射器SZK(结论)

    1121: [POI2008]激光发射器SZK Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 916  Solved: 759[Submit][Sta ...

  4. Java8080端口被占用解决办法

    netstat -ano | findstr 8080 taskkill -pid 3196-f

  5. 高德,百度,Google地图定位偏移以及坐标系转换

    一.在进行地图开发过程中,我们一般能接触到以下三种类型的地图坐标系: 1.WGS-84原始坐标系 一般用国际GPS纪录仪记录下来的经纬度,通过GPS定位拿到的原始经纬度,Google和高德地图定位的的 ...

  6. mac 安装 swoole 可能会出现的错误

    请先看完之后再操作 一.用pecl安装swoole(没有安装起来) 2018年4月,由于homebrew的变动,导致无法使用brew install的方式安装php的扩展,现在改为用pecl安装,pe ...

  7. vagrant使用centos的环境安装..

    vagrant这货挺好用的..简要就是, 下好virtualbox, vagrant, 然后下个你需要的box. 然后vagrant box add boxname boxpath就行. 然后在合适的 ...

  8. ACM_小G的循环

    小G的循环 Time Limit: 2000/1000ms (Java/Others) Problem Description: 一回生,二回熟,三回就腻,小G用for,while循环用得太多了,累觉 ...

  9. docker容器如何安装vim

    mv /etc/apt/sources.list /etc/apt/sources.list.bak && \     echo "deb http://mirrors.16 ...

  10. [转]在 Linux 下使用 RAID

    转自:http://www.linuxidc.com/Linux/2015-08/122191.htm RAID 的意思是廉价磁盘冗余阵列(Redundant Array of Inexpensive ...