介绍
该笔记是在学习拉勾教育 Java 高薪训练营后,结合课程和老师的视频,自己跟踪源码后做的笔记。
Executor 结构
如下图,Executor 的默认实现类为 BaseExecutor,实现 Executor 接口的大部分功能。
- BaseExecutor,Executor 接口的默认实现类,实现 Executor 接口的大部分功能;
- ClosedExecutor,已关闭的 Executor;
- CachingExecutor,支持二级缓存的 Executor 的实现类。先从缓存中查询结果,存在就返回。否则会给一级缓存执行器(BatchExecutor、ReuseExecutor、SimpleExecutor)去获取数据;
- BatchExecutor,批量执行的 Executor 实现类,缓存多个 Statement 对象,等待统一执行;
- ReuseExecutor,可重用的 Executor 实现类,指重复使用 Statement;
- 每次开始读或写操作,优先从缓存中获取对应的 Statement 对象。如果不存在,才进行创建,并保存到 Map 中;
- 执行完成后,不关闭该 Statement 对象。
- SimpleExecutor,简单的 Executor 实现类,默认使用的执行器;
- 每次开始读或写操作,都创建对应的 Statement 对象;
- 执行完成后,关闭该 Statement 对象。
区别
- CachingExecutor,二级缓存执行器,二级缓存没获取到,在走一级缓存流程;
- BatchExecutor,先缓存多个 Statement 对象,在统一执行;
- ReuseExecutor,重复使用 Statement,先从缓存中获取 Statement;
- SimpleExecutor,执行一次就创建一个 Statement,执行完就关闭。
newExecutor
为创建执行器代码。
- 根据 ExecutorType 类型来选择一级缓存执行器,BATCH 为 BatchExecutor,REUSE 为 ReuseExecutor,其余都为 SimpleExecutor;
- 看出二级缓存 CachingExecutor 会存入一个一级缓存执行器,先进行二级缓存查找,找不到在调用一级缓存执行器查找。
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
// 获得执行器类型
executorType = executorType == null ? defaultExecutorType : executorType; // 使用默认
executorType = executorType == null ? ExecutorType.SIMPLE : executorType; // 使用 ExecutorType.SIMPLE
// 创建对应实现的 Executor 对象
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;
}
设计模式
Executor 接口 -> 抽象类 BaseExecutor -> 具体子类 BatchExecutor,这种结构典型使用了模板方法的设计模式,在抽象方法中封装了整体逻辑流程,其中的某个方法则为抽象方法,由子类实现。
如下代码,BaseExecutor#update 封装了更新的整体流程,而 doUpdate 为抽象方法,由具体子类实现。
@Override
public int update(MappedStatement ms, Object parameter) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
// 已经关闭,则抛出 ExecutorException 异常
if (closed) {
throw new ExecutorException("Executor was closed.");
}
// 清空本地缓存
clearLocalCache();
// 执行写操作
return doUpdate(ms, parameter);
}
protected abstract int doUpdate(MappedStatement ms, Object parameter)
throws SQLException;
SimpleExecutor#doUpdate
继承抽象类 BaseExecutor 并实现其抽象方法 doUpdate。看出代码逻辑,会创建 StatementHandler 对象,然后执行 update 操作,最后关闭 StatementHandler。
@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());
// 执行 StatementHandler ,进行写操作
return handler.update(stmt);
} finally {
// 关闭 StatementHandler 对象
closeStatement(stmt);
}
}