执行器逻辑大致是这样的
由SqlSession定义门面,然后核心的执行组件是Executor执行器,它也是一个接口,定义了门面api所需要的接口,由baseExecutor抽象类来实现它,还有一级缓存以及获取连接等逻辑,定义了抽象方法doquery和doUpdate来交付给它的子类来完成不同的执行过程。
simpleExecutor简单执行器:同样的sql每执行一次都要创建一个预编译的对象,prepareStatement
reuseExecutor可重用执行器:同样的sql执行多次只创建一个预编译对象
batchExecutor批处理执行器:可以实现批处理更新操作,将更新的信息一次性刷新到数据库中,但是需要手动刷新
我们开始观察源码:
进入query方法
进入重载的query方法
我们进入
queryFromDatabase方法
由此,我们的执行器方法就已经执行结束了
然后我们在看第二次同样的查询:
同样的sql语句到这里会生成同样的key
然后就是list被赋值,返回
接下来我们看缓存执行器
实现二级缓存的逻辑是这样的
下面我们做一个二级缓存执行器的测试
发现依然是获取缓存sql的key和获取动态sql
然后我们再进入下面的query方法
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
//获取对应mapper里的配置信息,如果配置了二级缓存,则返回值不为空
Cache cache = ms.getCache();
if (cache != null) {
//刷新二级缓存
flushCacheIfRequired(ms);
//如果使用了二级缓存,且没有使用自定义的结果处理器
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, boundSql);
@SuppressWarnings("unchecked")
//从二级缓存中查询对应的key的数据,并赋值给list
List<E> list = (List<E>) tcm.getObject(cache, key);
/*如果list仍然为空(说明二级缓存中没有对应的数据),则使用传入的执行器处理该sql,从一级缓
存或者数据库中获取结果集*/
if (list == null) {
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);
}