mybatis源码阅读-执行器Executor(四)
说明
前面二看到了 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(四)的更多相关文章
- mybatis源码阅读-执行器StatementHandle和ParameterHandler(五)
StatementHandle 类图 各个实现类的作用 SimpleStatementHandler 用于使用Statement操作数据库(不会使用参数化查询?) PreparedStatementH ...
- Mina源码阅读笔记(四)—Mina的连接IoConnector2
接着Mina源码阅读笔记(四)-Mina的连接IoConnector1,,我们继续: AbstractIoAcceptor: 001 package org.apache.mina.core.rewr ...
- mybatis源码-解析配置文件(四-1)之配置文件Mapper解析(cache)
目录 1. 简介 2. 解析 3 StrictMap 3.1 区别HashMap:键必须为String 3.2 区别HashMap:多了成员变量 name 3.3 区别HashMap:key 的处理多 ...
- Mybatis源码阅读-配置文件及映射文件解析
Mybatis源码分析: 1.配置文件解析: 1.1源码阅读入口: org.apache.ibatis.builder.xml.XMLConfigBuilder.parse(); 功能:解析全局配置文 ...
- Mybatis源码详解系列(四)--你不知道的Mybatis用法和细节
简介 这是 Mybatis 系列博客的第四篇,我本来打算详细讲解 mybatis 的配置.映射器.动态 sql 等,但Mybatis官方中文文档对这部分内容的介绍已经足够详细了,有需要的可以直接参考. ...
- mybatis源码-解析配置文件(四)之配置文件Mapper解析
在 mybatis源码-解析配置文件(三)之配置文件Configuration解析 中, 讲解了 Configuration 是如何解析的. 其中, mappers作为configuration节点的 ...
- Mybatis源码阅读 之 玩转Executor
承接上篇博客, 本文探究MyBatis中的Executor, 如下图: 是Executor体系图 本片博客的目的就是探究如上图中从顶级接口Executor中拓展出来的各个子执行器的功能,以及进一步了解 ...
- mybatis源码阅读-Transaction和TransactionFactory(四)
Transaction 类图 接口定义 public interface Transaction { Connection getConnection() throws SQLException; v ...
- mybatis源码阅读(动态代理)
这一篇文章主要是记录Mybatis的动态代理学习成果,如果对源码感兴趣,可以看一下上篇文章 https://www.cnblogs.com/ChoviWu/p/10118051.html 阅读本篇的 ...
随机推荐
- Python三次登陆
题目:Python实现三次登陆 不要急于马上把三次登陆写出来,一定要将复杂的程序简单化,必须一步一步地去扩展,这样才保证不会出错. 步骤一:实现简单的一次登陆 # 事先定义 user = 'dark_ ...
- hadoop-Combiner作用用法
文章来源http://blog.csdn.net/ipolaris/article/details/8723782 reduce的输入每个key所对应的value将是一大串1,但处理的文本很多时,这一 ...
- 解决UTF-8方法归纳
1:通过spring配置过滤器解决 <!-- 配置Spring提供的字符编码过滤器 --> <filter> <filter-name>SpringCharacte ...
- Web开发必须知道的知识点
Web前端必须知道 一.常用那几种浏览器测试.有哪些内核(Layout Engine) 1.浏览器:IE,Chrome,FireFox,Safari,Opera. 2.内核:Trident,Gecko ...
- JavaScript--引用JS外部文件
通过前面知识学习,我们知道使用<script>标签在HTML文件中添加JavaScript代码,如图: JavaScript代码只能写在HTML文件中吗?当然不是,我们可以把HTML文件和 ...
- hihocode 编程练习赛17
1. f1 score 首先了解f1 score的计算方法, 我记得是学信息检索知道的, 然后简单处理就行. 由于我写的比较麻烦, 中间处理过程引入了一些除数为0的情况,导致错了很多次.其实是很简单的 ...
- python框架之Flask基础篇(四)-------- 其他操作
1.蓝图 要用蓝图管理项目,需要导入的包是:from flask import Buleprint 具体大致分为三步: 1.先在子模块中导入蓝图包,然后再创建蓝图对象. 2.然后将子模块中的视图函数存 ...
- 二次封装OKHttp网络框架(1)
1. 框架功能简介:暂时只有get.post两个请求 2. 请求的主要流程和区别: 2.1 get请求: (1)创建请求客户的 OkHttpClient对象 (2)创建请求构建器 Request.Bu ...
- PHP流程控制语句(if,foreach,break......)
背景:PHP程序中,必不可少的要用到流程控制语句.这次对于流程控制语句进行一些总结. 条件控制语句和循环控制语句是两种基本的语法结构,它们都是用来控制程序执行流程.也是构成程序的主要语法基础. 一.程 ...
- (转)44 道 JavaScript 难题
JavaScript Puzzlers原文 1. ["1", "2", "3"].map(parseInt) 答案:[1, NaN, N ...