SQL执行器Executor
-
由上篇文章分析可知,mybatis在内部主要通过executor包的Executor来调用JDBC的相关API来完成SQL语句的执行。Executor通常绑定到SqlSession中,即Executor作为SqlSession对象的一个内部属性,故Executor的对象创建是与SqlSession的对象创建一起的。
-
SqlSession对象是由SqlSessionFactory来创建的,所以SqlSessionFactory在创建SqlSession对象时,也会创建对应的Executor对象。DefaultSqlSessionFactory的具体如下:
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; try { final Environment environment = configuration.getEnvironment(); final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); // 创建SQL执行器executor final Executor executor = configuration.newExecutor(tx, execType); // 将配置configuration,SQL执行器executor作为参数SqlSession对象 return new DefaultSqlSession(configuration, executor, autoCommit); } catch (Exception e) { closeTransaction(tx); // may have fetched a connection so lets call close() throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } }
-
Configuration创建Executor对象的newExecutor方法实现如下:如果在mybatisConfig.xml配置了cacheEnabled为true,则使用Executor接口的CachingExecutor实现类,其中CachingExecutor为使用二级缓存的SQL执行器。而一级缓存是默认开启的。
// SQL执行器,主要负责解析参数,调用底层的JDBC接口来执行SQL 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来包装该executor if (cacheEnabled) { executor = new CachingExecutor(executor); } executor = (Executor) interceptorChain.pluginAll(executor); return executor; }
-
缓存主要是在查询select操作中使用。
一级缓存实现
-
一级缓存是默认开启的,且不能通过配置来显式关闭一级缓存(不过可以设置一级缓存级别为STATEMENT来关闭),所以是在顶层抽象基类BaseExecutor中定义,核心实现如下:其中一级缓存为使用HashMap的包装类caching包的PerpetualCache来实现。
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { BoundSql boundSql = ms.getBoundSql(parameter); // 缓存key的生成 CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql); return query(ms, parameter, rowBounds, resultHandler, key, boundSql); } public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId()); if (closed) { throw new ExecutorException("Executor was closed."); } if (queryStack == 0 && ms.isFlushCacheRequired()) { clearLocalCache(); } List<E> list; try { queryStack++; list = resultHandler == null ? (List<E>) localCache.getObject(key) : null; if (list != null) { // 从缓存获取指定SQL的结果,而不用去数据库查询 handleLocallyCachedOutputParameters(ms, key, parameter, boundSql); } else { // 去数据库查询 list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); } } finally { queryStack--; } // 由于SqlSession不是线程安全的,故任何时候只存在一个线程操作,故queryStack总是0的 if (queryStack == 0) { for (DeferredLoad deferredLoad : deferredLoads) { deferredLoad.load(); } // issue #601 deferredLoads.clear(); // 如果是STATEMENT,则每次执行完查询都清空缓存,故其实是没有缓存 if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) { // issue #482 clearLocalCache(); } } return list; }
-
缓存key的生成算法如下:
// 缓存key @Override public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) { if (closed) { throw new ExecutorException("Executor was closed."); } CacheKey cacheKey = new CacheKey(); cacheKey.update(ms.getId()); cacheKey.update(rowBounds.getOffset()); cacheKey.update(rowBounds.getLimit()); cacheKey.update(boundSql.getSql()); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry(); // mimic DefaultParameterHandler logic for (ParameterMapping parameterMapping : parameterMappings) { if (parameterMapping.getMode() != ParameterMode.OUT) { Object value; String propertyName = parameterMapping.getProperty(); if (boundSql.hasAdditionalParameter(propertyName)) { value = boundSql.getAdditionalParameter(propertyName); } else if (parameterObject == null) { value = null; } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { value = parameterObject; } else { MetaObject metaObject = configuration.newMetaObject(parameterObject); value = metaObject.getValue(propertyName); } cacheKey.update(value); } } if (configuration.getEnvironment() != null) { // issue #176 cacheKey.update(configuration.getEnvironment().getId()); } return cacheKey; }
二级缓存实现
-
由以上分析,如果开启了二级缓存,则SqlSessionFactory在创建SqlSession对象时,同步创建的是类型为CachingExecutor的SQL执行器,故后续通过该SqlSession执行的查询操作都是通过该CachingExecutor对象来执行SQL调用,CachingExecutor的查询方法query定义如下:
// 在Executor级别实现二级缓存,这是一个包装类,由所有executor共享, // 所以所有executor,即所有SqlSession共享这个Executor提供的缓存 public class CachingExecutor implements Executor { // 被包装的实际执行的executor private final Executor delegate; // 二级缓存管理器,内部维护了各个namespace对应的二级缓存 private final TransactionalCacheManager tcm = new TransactionalCacheManager(); ... @Override public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { // 获取该语句对应的namespace关联的二级缓存 Cache cache = ms.getCache(); if (cache != null) { flushCacheIfRequired(ms); if (ms.isUseCache() && resultHandler == null) { ensureNoOutParams(ms, boundSql); @SuppressWarnings("unchecked") List<E> list = (List<E>) tcm.getObject(cache, key); // 二级缓存没有,则交给被包装的executor去查询,即可能是从一级缓存获取,如果一级缓存也没有,则查询数据库 if (list == null) { list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); tcm.putObject(cache, key, list); // issue #578 and #116 } return list; } } // 如果缓存没有,则执行数据库查询获取 return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); } ... }