一、执行器的构建
XMLConfigBuilder
private void parseConfiguration(XNode root) {
settingsElement(settings);
}
private void settingsElement(Properties props) {
configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));
}
DefaultSqlSessionFactory implements SqlSessionFactory
@Override
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false); // DefaultExecutorType -->SIMPLE
}
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
// execType == SIMPLE
final Executor executor = configuration.newExecutor(tx, execType);
// 返回DefaultSqlSession
return new DefaultSqlSession(configuration, executor, autoCommit);
}
Configuration
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executor = new SimpleExecutor(this, transaction);
// 默认值是true,所以默认构建的执行器就是CachingExecutor
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
executor = (Executor) interceptorChain.pluginAll(executor);
}
CachingExecutor
private final Executor delegate;
private final TransactionalCacheManager tcm = new TransactionalCacheManager();
public CachingExecutor(Executor delegate) {
// SimpleExecutor被委托给了CachingExecutor
this.delegate = delegate;
// SimpleExecutor被CachingExecutor封装
delegate.setExecutorWrapper(this);
}
DefaultSqlSeesion
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
// CachingExecutor
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
}
CachingExecutor
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
@Override
public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
// delegate是被委托对象SimpleExecutor, createCacheKey是BaseExecutor中的
return delegate.createCacheKey(ms, parameterObject, rowBounds, boundSql);
}
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
// 这里要看Cache的构建、MappedStatement的构建
// 如果在mapper.xml中配置了<cache/>,解析mapper.xml的时候会构建Cache,赋值到Configuration中的Map<String, Cache> caches和MappedStatement的Cache
Cache cache = ms.getCache();
}
二、Cache的构建
XMLMapperBuilder
// mapper.xml解析
// <cache type="" blocking="" eviction="" flushInterval="" readOnly="" size=""/>
// <cache-ref namespace=""/>
private void configurationElement(XNode context) {
cacheRefElement(context.evalNode("cache-ref"));
cacheElement(context.evalNode("cache"));
}
private void cacheElement(XNode context) {
if (context != null) {
// 默认PERPETUAL
String type = context.getStringAttribute("type", "PERPETUAL");
Class<? extends Cache> typeClass = typeAliasRegistry.resolveAlias(type);
// 默认LRU--我理解是清除缓存的机制
String eviction = context.getStringAttribute("eviction", "LRU");
Class<? extends Cache> evictionClass = typeAliasRegistry.resolveAlias(eviction);
Long flushInterval = context.getLongAttribute("flushInterval");
Integer size = context.getIntAttribute("size");
boolean readWrite = !context.getBooleanAttribute("readOnly", false);
boolean blocking = context.getBooleanAttribute("blocking", false);
Properties props = context.getChildrenAsProperties();
builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, blocking, props);
}
}
MapperBuilderAssistant
public Cache useNewCache(Class<? extends Cache> typeClass, Class<? extends Cache> evictionClass,
Long flushInterval,
Integer size,
boolean readWrite,
boolean blocking,
Properties props) {
Cache cache = new CacheBuilder(currentNamespace)
// 实现
.implementation(valueOrDefault(typeClass, PerpetualCache.class))
// 装饰器
.addDecorator(valueOrDefault(evictionClass, LruCache.class))
.clearInterval(flushInterval)
.size(size)
.readWrite(readWrite)
.blocking(blocking)
.properties(props)
.build();
configuration.addCache(cache);
currentCache = cache;
return cache;
}
CacheBuilder
public Cache build() {
setDefaultImplementations();
Cache cache = newBaseCacheInstance(implementation, id);
setCacheProperties(cache);
// issue #352, do not apply decorators to custom caches
if (PerpetualCache.class.equals(cache.getClass())) {
for (Class<? extends Cache> decorator : decorators) {
cache = newCacheDecoratorInstance(decorator, cache);
setCacheProperties(cache);
}
// 标准的装饰器
cache = setStandardDecorators(cache);
} else if (!LoggingCache.class.isAssignableFrom(cache.getClass())) {
cache = new LoggingCache(cache);
}
return cache;
}
// cacheClass是decorator
// 装饰器LruCache使用反射构造包含this.delegate = delegate;的对象,delegate当前是Perpetual
private Cache newCacheDecoratorInstance(Class<? extends Cache> cacheClass, Cache base) {
Constructor<? extends Cache> cacheConstructor = getCacheDecoratorConstructor(cacheClass);
try {
return cacheConstructor.newInstance(base);
} catch (Exception e) {
throw new CacheException("Could not instantiate cache decorator (" + cacheClass + "). Cause: " + e, e);
}
}
private Cache setStandardDecorators(Cache cache) {
try {
MetaObject metaCache = SystemMetaObject.forObject(cache);
if (size != null && metaCache.hasSetter("size")) {
metaCache.setValue("size", size);
}
if (clearInterval != null) {
cache = new ScheduledCache(cache);
((ScheduledCache) cache).setClearInterval(clearInterval);
}
if (readWrite) {
cache = new SerializedCache(cache);
}
cache = new LoggingCache(cache);
cache = new SynchronizedCache(cache);
if (blocking) {
cache = new BlockingCache(cache);
}
return cache;
} catch (Exception e) {
throw new CacheException("Error building standard cache decorators. Cause: " + e, e);
}
}
没有额外添加配置的情况下,最终的Cache对象
此时Configuration和MapperBuilderAssistant
protected final Map<String, Cache> caches = new StrictMap<>("Caches collection");
public void addCache(Cache cache) {
caches.put(cache.getId(), cache);
}
private Cache currentCache;
currentCache = cache;
三、MappedStatement构建
XMLMapperBuilder
private void configurationElement(XNode context) {
// 解析mapper.xml中的CRUD标签,此时builderAssistant中的currentCache已经赋值
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
}
private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
for (XNode context : list) {
final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
try {
statementParser.parseStatementNode();
} catch (IncompleteElementException e) {
configuration.addIncompleteStatement(statementParser);
}
}
}
XMLStatementBuilder
public void parseStatementNode() {
boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);
boolean useCache = context.getBooleanAttribute("useCache", isSelect);
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
resultSetTypeEnum, flushCache, useCache, resultOrdered,
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}
<select id="selectUser" resultType="com.lazy.snail.domain.User" useCache="false" flushCache="false">
select * from user
</select>
MapperBuilderAssistant
public MappedStatement addMappedStatement(
String id,
SqlSource sqlSource,
StatementType statementType,
SqlCommandType sqlCommandType,
Integer fetchSize,
Integer timeout,
String parameterMap,
Class<?> parameterType,
String resultMap,
Class<?> resultType,
ResultSetType resultSetType,
boolean flushCache,
boolean useCache,
boolean resultOrdered,
KeyGenerator keyGenerator,
String keyProperty,
String keyColumn,
String databaseId,
LanguageDriver lang,
String resultSets) {
MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType)
.resource(resource)
.fetchSize(fetchSize)
.timeout(timeout)
.statementType(statementType)
.keyGenerator(keyGenerator)
.keyProperty(keyProperty)
.keyColumn(keyColumn)
.databaseId(databaseId)
.lang(lang)
.resultOrdered(resultOrdered)
.resultSets(resultSets)
.resultMaps(getStatementResultMaps(resultMap, resultType, id))
.resultSetType(resultSetType)
.flushCacheRequired(valueOrDefault(flushCache, !isSelect))
.useCache(valueOrDefault(useCache, isSelect))
// currentCache被赋值给了ms
.cache(currentCache);
ParameterMap statementParameterMap = getStatementParameterMap(parameterMap, parameterType, id);
if (statementParameterMap != null) {
statementBuilder.parameterMap(statementParameterMap);
}
MappedStatement statement = statementBuilder.build();
configuration.addMappedStatement(statement);
return statement;
}
总结
- 1.在核心配置文件中,设置全局配置属性cacheEnabled="true",默认为true,不需要设置
- 2.在映射文件中设置标签
- 3.二级缓存必须在SqlSession关闭或提交之后有效
- 4.查询的数据所转换的实体类类型必须实现序列化的接口