mybatis CachingExecutor的query()方法

 

org.apache.ibatis.executor.CachingExecutor#query()   先从MappedStatement中获取缓存对象(在xml文件中配置的cache的对象,这里即EhcacheCache类的对象 )

<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
  1. 如果缓存对象为空,则开始执行delegate.query(),这里的delegate就是封装的其他三种类型的Executer
  2. 如果缓存对象不为空,则尝试从缓存取list。如果获取到的list为空,就执行delegate.query(),执行过后就将结果放入缓存
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
        throws SQLException {
    //从MappedStatement中获取缓存对象,一个sqlId对应一个MappedStatement的对象
    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);
            if (list == null) {
                //缓存中获取查询结果为空,执行包装的Executer的query()方法
                list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
                //将查询到的结果放到缓存中
                tcm.putObject(cache, key, list); // issue #578 and #116
            }
            return list;
        }
    }
    //如果获取到的缓存对象为空,则执行包装的Executer的query()方法
    return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

以上是一个简单且不太准确的描述,那下面看下真正的缓存吧,

 

//尝试从缓存中获取查询结果
List<E> list = (List<E>) tcm.getObject(cache, key);

首先看下tcm,tcm是TransactionalCacheManager类的一个对象,也是CachingExecutor的一个属性。以下代码中,在创建以一个CachingExecutor对象的同时,也创建了一个TransactionalCacheManager类的对象。

public class CachingExecutor implements Executor {
    private Executor delegate;
    private TransactionalCacheManager tcm = new TransactionalCacheManager();
    ...
}

接着就看下TransactionalCacheManager.java类,这个类有一个以Cache为key,TransactionalCache为value的map类型的数据结构transactionalCaches 。也是在创建TransactionalCacheManager的时候,该对象就创建出来了

public class TransactionalCacheManager {

    private Map<Cache, TransactionalCache> transactionalCaches = new HashMap<Cache, TransactionalCache>();
    ···
}

紧接着,还是要再看下TransactionalCache这个类,就只看下构造函数就行。封装了Cache对象,又多出一个map和一个set

public TransactionalCache(Cache delegate) {
    this.delegate = delegate;
    this.clearOnCommit = false;
    this.entriesToAddOnCommit = new HashMap<Object, Object>();
    this.entriesMissedInCache = new HashSet<Object>();
}

简单的了解下整个数据的结构,就看下tcm.getObject(cache, key); 这个方法

public Object getObject(Cache cache, CacheKey key) {
    return getTransactionalCache(cache).getObject(key);
}

接着看下getTransactionalCache(cache);  这行代码就是根据cache对象获取TransactionalCache对象

private TransactionalCache getTransactionalCache(Cache cache) {
    //transactionalCaches = new HashMap<Cache, TransactionalCache>(),transactionalCaches是一个以Cache为key,TransactionalCache为value的map类型的数据结构
    TransactionalCache txCache = transactionalCaches.get(cache);
     //如果获取到的txCache(TransactionalCache)是空的,则初始化,并放到transactionalCaches中去
    if (txCache == null) {
        txCache = new TransactionalCache(cache);
        transactionalCaches.put(cache, txCache);
    }
    //返回txCache
    return txCache;
}

再看下TransactionalCache.getObject(key); 就是从cache就获取缓存内容然后返回;

public Object getObject(Object key) {
    // issue #116 这里的delegate就是ms的cache(具体看下TransactionalCache的构造函数)
    Object object = delegate.getObject(key);
    if (object == null) {
        entriesMissedInCache.add(key);
    }
    // issue #146
    if (clearOnCommit) {
        return null;
    } else {
        return object;
    }
}

以上是缓存的获取,接着看下缓存的添加

tcm.putObject(cache, key, list);

直接看下这个方法吧,

public void putObject(Cache cache, CacheKey key, Object value) {
    getTransactionalCache(cache).putObject(key, value);
}

getTransactionalCache(cache) 方法就不说了,在读取缓存内容的时候已经说过了,就是从transactionalCaches中获取txCache对象;

看下TransactionalCache.putObject(key, value)方法吧。

public void putObject(Object key, Object object) {
    //private Map<Object, Object> entriesToAddOnCommit;,将从数据库查出来的结果放到entriesToAddOnCommit中,并没有放到ms的cache中去
    entriesToAddOnCommit.put(key, object);
}

将从数据库查出来的结果放到entriesToAddOnCommit中,并没有放到ms的cache中去,而读取的时候,却是通过TransactionalCache从ms的cache中读取的。别着急,看下org.apache.ibatis.executor.CachingExecutor#commit方法

public void commit(boolean required) throws SQLException {
    delegate.commit(required);
    tcm.commit();
}

看到熟悉的tcm,就看下tcm.commit();吧

public void commit() {
    //transactionalCaches = new HashMap<Cache, TransactionalCache>();
    //遍历transactionalCaches的values。执行其commit方法
    for (TransactionalCache txCache : transactionalCaches.values()) {
        txCache.commit();
    }
}

那接着看txCache.commit();的方法

public void commit() {
    if (clearOnCommit) {
        delegate.clear();
    }
    flushPendingEntries();
    reset();
}

接着是flushPendingEntries(); 循环entriesToAddOnCommit,放到cache中。至此,缓存的获取以及添加都差不多了

private void flushPendingEntries() {
    //delegate是cache对象,看TransactionalCache的构造方法,循环entriesToAddOnCommit,放到cache中
    for (Map.Entry<Object, Object> entry : entriesToAddOnCommit.entrySet()) {
        delegate.putObject(entry.getKey(), entry.getValue());
    }
    for (Object entry : entriesMissedInCache) {
        if (!entriesToAddOnCommit.containsKey(entry)) {
            delegate.putObject(entry, null);
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值