赞
踩
Mybatis源码系列文章
Mybatis源码解析(四):sql语句及#{}、${}的解析
Mybatis源码解析(五):SqlSession会话的创建

演示一

演示二

演示三

private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { List<E> list; // 1. 首先向本地缓存中存入一个ExecutionPlaceholder的枚举类占位value localCache.putObject(key, EXECUTION_PLACEHOLDER); try { // 2. 执行doQuery方法 list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql); } finally { // 3. 执行完成移除这个key localCache.removeObject(key); } // 4. 查询结果存入缓存中 localCache.putObject(key, list); // 5. 如果MappedStatement的类型为CALLABLE,则向localOutputParameterCache缓存中存入value为parameter的缓存 if (ms.getStatementType() == StatementType.CALLABLE) { localOutputParameterCache.putObject(key, parameter); } return list; }
查看一级缓存对象PerpetualCache localCache
public class PerpetualCache implements Cache { private final String id; private final Map<Object, Object> cache = new HashMap<>(); @Override public void putObject(Object key, Object value) { cache.put(key, value); } @Override public Object getObject(Object key) { return cache.get(key); } ... }
查看一级缓存对象PerpetualCache的位置

进入udpate源码
@Override
public int update(MappedStatement ms, Object parameter) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
if (closed) {
throw new ExecutorException("Executor was closed.");
}
clearLocalCache();
return doUpdate(ms, parameter);
}
@Override
public void clearLocalCache() {
if (!closed) {
localCache.clear();
localOutputParameterCache.clear();
}
}

演示一

演示二

捋一下xml与对象之间的关系
<cache>标签解析内容
private void cacheElement(XNode context) { if (context != null) { // 解析<cache>标签type属性的值,在这可以自定义type的值,比如redisCache,如果没有指定默认就是PERPETUAL String type = context.getStringAttribute("type", "PERPETUAL"); Class<? extends Cache> typeClass = typeAliasRegistry.resolveAlias(type); // 获取负责过期的eviction对象,默认策略为LRU String eviction = context.getStringAttribute("eviction", "LRU"); Class<? extends Cache> evictionClass = typeAliasRegistry.resolveAlias(eviction); // 清空缓存的频率 0代表不清空 Long flushInterval = context.getLongAttribute("flushInterval"); // 缓存容器的大小 Integer size = context.getIntAttribute("size"); // 是否只读 boolean readWrite = !context.getBooleanAttribute("readOnly", false); // 是否阻塞 boolean blocking = context.getBooleanAttribute("blocking", false); // 获得Properties属性 Properties props = context.getChildrenAsProperties(); builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, blocking, props); } }
Cache对象创建方法
public Cache useNewCache(Class<? extends Cache> typeClass, Class<? extends Cache> evictionClass, Long flushInterval, Integer size, boolean readWrite, boolean blocking, Properties props) { // 1.生成cache对象 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(); // 2.添加到configuration中 configuration.addCache(cache); // 3.并赋值给MapperBuilderAssistant中的currentCache属性 currentCache = cache; return cache; }

MappedStatement对象下

Configuration对象下
public class Configuration {
protected final Map<String, Cache> caches = new StrictMap<>("Caches collection");
...
public void addCache(Cache cache) {
caches.put(cache.getId(), cache);
}
...
}
@Override public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { // 获取二级缓存 Cache cache = ms.getCache(); if (cache != null) { // 刷新二级缓存 (存在缓存且flushCache为true时) flushCacheIfRequired(ms); if (ms.isUseCache() && resultHandler == null) { ensureNoOutParams(ms, boundSql); @SuppressWarnings("unchecked") // 从二级缓存中查询数据 List<E> list = (List<E>) tcm.getObject(cache, key); // 如果二级缓存中没有查询到数据,则查询一级缓存及数据库 if (list == null) { // 委托给BaseExecutor执行 list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); // 将查询结果 要存到二级缓存中(注意:此处只是存到map集合中,没有真正存到二级缓存中) tcm.putObject(cache, key, list); // issue #578 and #116 } return list; } } // 委托给BaseExecutor执行 return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }

tcm对象
public class CachingExecutor implements Executor {
private final Executor delegate;
private final TransactionalCacheManager tcm = new TransactionalCacheManager();
...
}
public class TransactionalCacheManager { // Cache 与 TransactionalCache 的映射关系表 private final Map<Cache, TransactionalCache> transactionalCaches = new HashMap<>(); public void clear(Cache cache) { // 获取 TransactionalCache 对象,并调用该对象的 clear 方法,下同 getTransactionalCache(cache).clear(); } public Object getObject(Cache cache, CacheKey key) { // 直接从TransactionalCache中获取缓存 return getTransactionalCache(cache).getObject(key); } public void putObject(Cache cache, CacheKey key, Object value) { // 直接存入TransactionalCache的缓存中 getTransactionalCache(cache).putObject(key, value); } ... }
进入tcm.putObject方法
public void putObject(Cache cache, CacheKey key, Object value) {
// 直接存入TransactionalCache的缓存中
getTransactionalCache(cache).putObject(key, value);
}
进入getTransactionalCache方法
private TransactionalCache getTransactionalCache(Cache cache) {
// 从映射表中获取 TransactionalCache
return MapUtil.computeIfAbsent(transactionalCaches, cache, TransactionalCache::new);
}
进入putObject方法
public class TransactionalCache implements Cache {
...
/**
* // 在事务被提交前,所有从数据库中查询的结果将缓存在此集合中
*/
private final Map<Object, Object> entriesToAddOnCommit;
@Override
public void putObject(Object key, Object object) {
// 将键值对存入到 entriesToAddOnCommit 这个Map中中,而非真实的缓存对象 delegate 中
entriesToAddOnCommit.put(key, object);
}
...
}
public Object getObject(Cache cache, CacheKey key) {
// 直接从TransactionalCache中获取缓存
return getTransactionalCache(cache).getObject(key);
}
进入getObject方法
public class TransactionalCache implements Cache { /** * 委托的 Cache 对象。 * * 实际上,就是二级缓存 Cache 对象。 */ private final Cache delegate; /** * 提交时,清空 {@link #delegate} * * 初始时,该值为 false * 清理后{@link #clear()} 时,该值为 true ,表示持续处于清空状态 */ private boolean clearOnCommit; /** * 在事务被提交前,当缓存未命中时,CacheKey 将会被存储在此集合中 */ private final Set<Object> entriesMissedInCache; @Override public Object getObject(Object key) { // issue #116 // 查询的时候是直接从delegate中去查询的,也就是从真正的缓存对象中查询 Object object = delegate.getObject(key); // 如果不存在,则添加到 entriesMissedInCache 中 if (object == null) { // 缓存未命中,则将 key 存入到 entriesMissedInCache 中 entriesMissedInCache.add(key); } // issue #146 // 如果 clearOnCommit 为 true ,表示处于持续清空状态,则返回 null if (clearOnCommit) { return null; } else { // 返回 value return object; } } ... }
@Override
public void commit(boolean required) throws SQLException {
delegate.commit(required);
tcm.commit();
}
public void commit() {
for (TransactionalCache txCache : transactionalCaches.values()) {
txCache.commit();
}
}
public void commit() {
// 如果 clearOnCommit 为 true ,则清空 delegate 缓存
if (clearOnCommit) {
delegate.clear();
}
// 将 entriesToAddOnCommit、entriesMissedInCache 刷入 delegate(cache) 中
flushPendingEntries();
// 重置
reset();
}
flushPendingEntries真正存入二级缓存方法
private void flushPendingEntries() {
// 将 entriesToAddOnCommit 中的内容转存到 delegate 中
for (Map.Entry<Object, Object> entry : entriesToAddOnCommit.entrySet()) {
// 在这里真正的将entriesToAddOnCommit的对象逐个添加到delegate中,只有这时,二级缓存才真正的生效
delegate.putObject(entry.getKey(), entry.getValue());
}
}
二级缓存存取总结:
@Override
public int update(MappedStatement ms, Object parameterObject) throws SQLException {
flushCacheIfRequired(ms);
return delegate.update(ms, parameterObject);
}
private void flushCacheIfRequired(MappedStatement ms) {
Cache cache = ms.getCache();
if (cache != null && ms.isFlushCacheRequired()) {
tcm.clear(cache);
}
}
public void clear(Cache cache) {
// 获取 TransactionalCache 对象,并调用该对象的 clear 方法,下同
getTransactionalCache(cache).clear();
}
进入clear方法
@Override
public void clear() {
// 标记 clearOnCommit 为 true
clearOnCommit = true;
// 清空 entriesToAddOnCommit
entriesToAddOnCommit.clear();
}
进入commit方法
public void commit() {
// 如果 clearOnCommit 为 true ,则清空 delegate 缓存
if (clearOnCommit) {
delegate.clear();
}
// 将 entriesToAddOnCommit、entriesMissedInCache 刷入 delegate(cache) 中
flushPendingEntries();
// 重置
reset();
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。