Executor
**
* 执行器接口
* @author Clinton Begin
*/
public interface Executor {
// 空的handler对象的枚举
ResultHandler NO_RESULT_HANDLER = null;
// 更新 or 插入 or 删除,由传入的 MappedStatement 的 SQL 所决定
int update(MappedStatement ms, Object parameter) throws SQLException;
// 查询,带 ResultHandler + CacheKey + BoundSql
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;
// 查询,带 ResultHandler
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;
// 查询,返回值为 Cursor
<E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;
// 刷入批处理语句
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();
// 设置包装的 Executor 对象
void setExecutorWrapper(Executor executor);
}
执行器的顶级接口,所有的数据操作最终使用这里的方法
其类的实现关系
下面我们来看看相关实现类的逻辑
BaseExecutor
是一个抽象类实现了Executor一些基础方法,其主要的数据操作方法,留给子类实现
// 更新和查询操作没有实现,由子类实现
protected abstract int doUpdate(MappedStatement ms, Object parameter)
throws SQLException;
protected abstract List<BatchResult> doFlushStatements(boolean isRollback)
throws SQLException;
protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
throws SQLException;
protected abstract <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql)
throws SQLException;
主要实现了事务和缓存相关的逻辑
// 提交
@Override
public void commit(boolean required) throws SQLException {
if (closed) {
throw new ExecutorException("Cannot commit, transaction is already closed");
}
// 清空本地缓存
clearLocalCache();
// 刷入批处理语句
flushStatements();
// 是否要求提交事务,如果是,则提交事务
if (required) {
transaction.commit();
}
}
// 回滚
@Override
public void rollback(boolean required) throws SQLException {
if (!closed) {
try {
// 清空本地缓存
clearLocalCache();
// 刷入批处理数据
flushStatements(true);
} finally {
if (required) {
// 假如需要回滚事务,进行回滚
transaction.rollback();
}
}
}
}
....
缓存
@Override
public void clearLocalCache() {
// 清理一级(本地)缓存
if (!closed) {
// 清理本地缓存,和参数缓存
localCache.clear();
localOutputParameterCache.clear();
}
}
....
SimpleExecutor
执行器的简单实现
doQuery
执行查询
// 类似其他的doUpdate
@Override
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 handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
// 初始化 StatementHandler 对象
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
// 获得连接
Connection connection = getConnection(statementLog);
// 创建Statement
stmt = handler.prepare(connection, transaction.getTimeout());
// 设置 SQL 上的参数,例如 PrepareStatement 对象上的占位符
handler.parameterize(stmt);
return stmt;
}
将mybatis对SQL的对象参数,封装成java的Statement进行数据操作
doQueryCursor
类似于doQuery只不过调用方法从
return handler.query(stmt, resultHandler);
修改为
return handler.queryCursor(stmt);
doUpdate
@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
// 获得配置
Configuration configuration = ms.getConfiguration();
// 创建StatementHandler
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
// 执行StatementHandler
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.update(stmt);
} finally {
// 关闭StatementHandler
closeStatement(stmt);
}
}
类似doQuery,其实里面逻辑无法是从select方法缓存update方法
doFlushStatements
// 不存在批量操作的情况,所以直接返回空数组
@Override
public List<BatchResult> doFlushStatements(boolean isRollback) {
return Collections.emptyList();
}
ReuseExecutor
可重用的 Executor 实现类,每次开始读或写操作,优先从缓存中获取对应的 Statement 对象。如果不存在,才进行创建。执行完成后,不关闭该 Statement 对象
其主要逻辑和SimpleExecutor区别不大,以doQuery为例子
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
Statement stmt = prepareStatement(handler, ms.getStatementLog());
return handler.query(stmt, resultHandler);
}
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
BoundSql boundSql = handler.getBoundSql();
String sql = boundSql.getSql();
// 判断是否存在对应的 Statement 对象
// 存在 从缓存中获得 Statement 或 PrepareStatement 对象
if (hasStatementFor(sql)) {
stmt = getStatement(sql);
// 设置事务超时时间
applyTransactionTimeout(stmt);
// 不存在
} else {
// 获得 Connection 对象
Connection connection = getConnection(statementLog);
// 创建 Statement 或 PrepareStatement 对象
stmt = handler.prepare(connection, transaction.getTimeout());
// 添加到缓存中
putStatement(sql, stmt);
}
// 设置 SQL 上的参数,例如 PrepareStatement 对象上的占位符
handler.parameterize(stmt);
return stmt;
}
private Statement getStatement(String s) {
return statementMap.get(s);
}
可以看到,他会先从缓存中获得PrepareStatement,假如不存在就会创建一个新的,
而在SimpleExecutor在执行完操作之后我们看到一句代码
closeStatement(stmt);
而ReuseExecutor是不存在的,ReuseExecutor执行完操作后不关闭Statement
doFlushStatements
@Override
public List<BatchResult> doFlushStatements(boolean isRollback) {
// 关闭缓存的 Statement 对象
for (Statement stmt : statementMap.values()) {
closeStatement(stmt);
}
statementMap.clear();
// 返回空集合
return Collections.emptyList();
}
执行批量Statements关闭操作
BatchExecutor
继承 BaseExecutor 抽象类,批量执行的 Executor 实现类
doQuery
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
throws SQLException {
Statement stmt = null;
try {
// 输入批处理
flushStatements();
// 配置,Statement处理,获得连接,Statement,然后设置参数,执行操作
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameterObject, rowBounds, resultHandler, boundSql);
Connection connection = getConnection(ms.getStatementLog());
stmt = handler.prepare(connection, transaction.getTimeout());
handler.parameterize(stmt);
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
其批处理的方法在flushStatements中
flushStatements
请过几次嵌套最终实现批处理的代码逻辑是
// org/apache/ibatis/executor/BatchExecutor.java
@Override
public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
try {
// 批处理
List<BatchResult> results = new ArrayList<>();
// 如果回滚,设置空
if (isRollback) {
return Collections.emptyList();
}
// 遍历 statementList 和 batchResultList 数组,逐个提交批处理
for (int i = 0, n = statementList.size(); i < n; i++) {
// 获得 Statement 和 BatchResult 对象
Statement stmt = statementList.get(i);
applyTransactionTimeout(stmt);
BatchResult batchResult = 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())) { //issue #141
for (Object parameter : parameterObjects) {
keyGenerator.processAfter(this, ms, stmt, parameter);
}
}
// Close statement to close cursor #1109
// 关闭 Statement 对象
closeStatement(stmt);
} catch (BatchUpdateException e) {
// 如果发生异常,则抛出 BatchExecutorException 异常
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(), e, results, batchResult);
}
// 添加到结果集
results.add(batchResult);
}
return results;
} finally {
// 关闭 Statement 们
for (Statement stmt : statementList) {
closeStatement(stmt);
}
// 置空 currentSql、statementList、batchResultList 属性
currentSql = null;
statementList.clear();
batchResultList.clear();
}
}
整体的逻辑
- 首先取出statementList 和 batchResultList 数组中的数据
- 然后依次提交批处理
- 处理完成后再循环statementList依次关闭对应的statement,然后清空statementList,batchResultList
- 然后上一层方法获得本次连接Connection connection = getConnection(ms.getStatementLog())
- 拿到执行的statement中进行执行并获得结果进行处理
二级缓存
CachingExecutor
支持二级缓存的 Executor 的实现类
// 事务缓存管理器
private final TransactionalCacheManager tcm = new TransactionalCacheManager();
其内部维持一个事务缓存管理器
query
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
// 获得缓存
Cache cache = ms.getCache();
// 缓存存在则执行里面逻辑,不存则是直接调用委托执行器 delegate 的对应的方法
if (cache != null) {
// 如果需要清空缓存,则进行清空
flushCacheIfRequired(ms);
// 当 MappedStatement#isUseCache() 方法,返回 true 时,才使用二级缓存
if (ms.isUseCache() && resultHandler == null) {
// 暂时忽略,存储过程相关
ensureNoOutParams(ms, boundSql);
@SuppressWarnings("unchecked")
// 缓存中获取结果
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
// 不存在则是直接调用委托执行器 delegate 的对应的方法
list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
- 其内部在执行操作的时候,会优先从缓存中取出数据。
直接调用委托方法
// 执行器
private final Executor delegate;
public CachingExecutor(Executor delegate) {
this.delegate = delegate;
delegate.setExecutorWrapper(this);
}
其内部维持一个Executor 对象,其他执行器接口的方法的实现,全部使用构造时候传入的执行器进行具体的实现。
TransactionalCacheManager
支持事务的缓存管理器,因为二级缓存是支持跨 Session 进行共享,此处需要考虑事务,那么,必然需要做到事务提交时,才将当前事务中查询时产生的缓存,同步到二级缓存中。这个功能,就通过 TransactionalCacheManager 来实现
public class TransactionalCacheManager {
// Cache 和 TransactionalCache 的映射
private final Map<Cache, TransactionalCache> transactionalCaches = new HashMap<>();
// 清空
public void clear(Cache cache) {
getTransactionalCache(cache).clear();
}
// 取值
public Object getObject(Cache cache, CacheKey key) {
return getTransactionalCache(cache).getObject(key);
}
// 存放
public void putObject(Cache cache, CacheKey key, Object value) {
getTransactionalCache(cache).putObject(key, value);
}
// 提交,循环值获得事务,执行提交
public void commit() {
for (TransactionalCache txCache : transactionalCaches.values()) {
txCache.commit();
}
}
// 回滚,循环值获得事务,执行回滚
public void rollback() {
for (TransactionalCache txCache : transactionalCaches.values()) {
txCache.rollback();
}
}
private TransactionalCache getTransactionalCache(Cache cache) {
return transactionalCaches.computeIfAbsent(cache, TransactionalCache::new);
}
}
其内部位置一个缓存的映射,key为Cache,value为TransactionalCache 。代码不算太麻烦,里面除了获取数据,也有提交和回滚的逻辑。
TransactionalCache
public class TransactionalCache implements Cache {
private static final Log log = LogFactory.getLog(TransactionalCache.class);
// 委托给cache,二级缓存
private final Cache delegate;
// 提交时,清空
private boolean clearOnCommit;
// 等待提交内容
private final Map<Object, Object> entriesToAddOnCommit;
// 查找不到的key集合
private final Set<Object> entriesMissedInCache;
public TransactionalCache(Cache delegate) {
this.delegate = delegate;
this.clearOnCommit = false;
this.entriesToAddOnCommit = new HashMap<>();
this.entriesMissedInCache = new HashSet<>();
}
@Override
public String getId() {
return delegate.getId();
}
@Override
public int getSize() {
return delegate.getSize();
}
@Override
public Object getObject(Object key) {
// issue #116
// 从缓存中查询结果,假如找不到将key保存到entriesMissedInCache
Object object = delegate.getObject(key);
if (object == null) {
entriesMissedInCache.add(key);
}
// issue #146
// 如果 clearOnCommit 为 true ,表示处于持续清空状态,则返回 null
if (clearOnCommit) {
return null;
} else {
return object;
}
}
@Override
public ReadWriteLock getReadWriteLock() {
return null;
}
@Override
public void putObject(Object key, Object object) {
// 暂存 KV 到 entriesToAddOnCommit 中
entriesToAddOnCommit.put(key, object);
}
@Override
public Object removeObject(Object key) {
return null;
}
@Override
public void clear() {
// 标记 clearOnCommit 为 true
clearOnCommit = true;
entriesToAddOnCommit.clear();
}
public void commit() {
// 如果 clearOnCommit 为 true ,则清空 delegate 缓存
if (clearOnCommit) {
delegate.clear();
}
// 将 entriesToAddOnCommit、entriesMissedInCache 刷入 delegate 中
flushPendingEntries();
// 重置
reset();
}
public void rollback() {
// 从 delegate 移除出 entriesMissedInCach
unlockMissedEntries();
reset();
}
// 重置缓存配置
private void reset() {
clearOnCommit = false;
entriesToAddOnCommit.clear();
entriesMissedInCache.clear();
}
private void flushPendingEntries() {
// 将 entriesToAddOnCommit 刷入 delegate 中
for (Map.Entry<Object, Object> entry : entriesToAddOnCommit.entrySet()) {
delegate.putObject(entry.getKey(), entry.getValue());
}
// 将 entriesMissedInCache 刷入 delegate 中
for (Object entry : entriesMissedInCache) {
if (!entriesToAddOnCommit.containsKey(entry)) {
delegate.putObject(entry, null);
}
}
}
private void unlockMissedEntries() {
for (Object entry : entriesMissedInCache) {
try {
delegate.removeObject(entry);
} catch (Exception e) {
log.warn("Unexpected exception while notifiying a rollback to the cache adapter."
+ "Consider upgrading your cache adapter to the latest version. Cause: " + e);
}
}
}
}
实现 Cache 接口,支持事务的 Cache 实现类,主要用于二级缓存中
可以看到针对缓存的最终操作是委托给 private final Cache delegate; java缓存实现类来进行的。
getObject
@Override
public Object getObject(Object key) {
// issue #116
// 从缓存中查询结果,假如找不到将key保存到entriesMissedInCache
Object object = delegate.getObject(key);
if (object == null) {
entriesMissedInCache.add(key);
}
// issue #146
// 如果 clearOnCommit 为 true ,表示处于持续清空状态,则返回 null
if (clearOnCommit) {
return null;
} else {
return object;
}
}
当无法获取的缓存的key会被保存在entriesMissedInCache中做个记录
putObject
@Override
public void putObject(Object key, Object object) {
// 暂存 KV 到 entriesToAddOnCommit 中
entriesToAddOnCommit.put(key, object);
}
数据并不会第一时间被保存在缓存中delegate,而是保存在entriesToAddOnCommit,中等待提交后才刷入缓存中
commit
public void commit() {
// 如果 clearOnCommit 为 true ,则清空 delegate 缓存
if (clearOnCommit) {
delegate.clear();
}
// 将 entriesToAddOnCommit、entriesMissedInCache 刷入 delegate 中
flushPendingEntries();
// 重置
reset();
}
private void flushPendingEntries() {
// 将 entriesToAddOnCommit 刷入 delegate 中
for (Map.Entry<Object, Object> entry : entriesToAddOnCommit.entrySet()) {
delegate.putObject(entry.getKey(), entry.getValue());
}
// 将 entriesMissedInCache 刷入 delegate 中
for (Object entry : entriesMissedInCache) {
if (!entriesToAddOnCommit.containsKey(entry)) {
delegate.putObject(entry, null);
}
}
}
当提交的时候才会将数据整体刷入缓存中
创建 Executor 对象
缓存的创建在Configuration里面
// org/apache/ibatis/session/Configuration.java
// 新建执行器的方法入口
public Executor newExecutor(Transaction transaction) {
return newExecutor(transaction, defaultExecutorType);
}
// 新建执行器
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
// 创建执行器类别
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
// 获取对应的执行器
Executor executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
// 如果开启缓存,创建 CachingExecutor 对象,进行包装
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
// 应用插件
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
public enum ExecutorType {
// SimpleExecutorc
SIMPLE,
// ReuseExecutor
REUSE,
// BatchExecutor
BATCH
}
总结
最后可以看到,执行器的多种实现类中,大多数只是对其他执行器的扩展最终执行业务的逻辑在SimpleExecutor中,而根据SimpleExecutor的逻辑中最终所有的操作是StatementHandler对java的Statement进行操作的逻辑。那么下一篇我们就看看StatementHandler的详细逻辑。