说明

前面二看到了 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. [模板]FWT

    写起来和fft很像,这里放个板子. 代码: #include<iostream> #include<cstdio> #include<cmath> #include ...

  2. Spark 机器学习------逻辑回归

    package Spark_MLlib import javassist.bytecode.SignatureAttribute.ArrayType import org.apache.spark.s ...

  3. E20170618-hm

    sentinel   n. 岗哨,哨兵; node   n. 节点; (计算机网络的) 节点; [医] 结节; 植物的节; traverse  n. 穿过; 横贯,横切; 横木; [建] 横梁; vt ...

  4. hibernate基础学习---hierbnate2级缓存

    1:开启二级缓存sessionFactory需要安装jar包 2:在实体类配置文件添加(配置二级缓存).我的配置文件是Account.hbm.xml <?xml version="1. ...

  5. P4049 [JSOI2007]合金

    传送门 我数学可能白学了-- 因为三个数加起来等于\(1\),那么只要用前两个数就能表示,那么就能把每一种金属看成一个二维向量.考虑只有两个向量的时候,设这两个向量为\(a,b\),那么一个向量\(c ...

  6. Akka源码分析-Persistence-AtLeastOnceDelivery

    使用过akka的应该都知道,默认情况下,消息是按照最多一次发送的,也就是tell函数会尽量把消息发送出去,如果发送失败,不会重发.但有些业务场景,消息的发送需要满足最少一次,也就是至少要成功发送一次. ...

  7. 观察者模式-C#实现

    定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新. 观察者模式有四个角色:抽象主题.具体主题.抽象观察者.具体观察者. 抽象主题:把所有观察者对象 ...

  8. [转]mysql的约束

    转自:http://blog.csdn.net/kqygww/article/details/8882990 MySQL中约束保存在information_schema数据库的table_constr ...

  9. Spring AOP(aspect oriented programming) 转载

    1.面向切面的基本原理 软件系统可以看成是由一组关注点组成的,其中,直接的业务关注点,是直切关注点.而为直切关注点提供服务的,就是横切关注点. 01.什么是面向切面编程 横切关注点:影响应用多处的功能 ...

  10. Android 使用MySQL直接访问数据库

    在实际项目中,一般很少直接访问MySQL数据库,一般情况下会通过http请求将数据传送到服务端,然后在服务端连接mysql数据库. 在android 中,会通过使用Jdbc 连接MySQL 服务器 p ...