在mybatis的主配置文件中,启动二级缓存配置
<settings> <setting name="cacheEnabled" value="true"/> </settings>
这个配置会再以后生成Executor的时候使用CachingExecutor而非 BaseExecutor
然后在映射的xml配置文件如UserMapper.xml中 对该实体启用缓存,简单点写直接添加
<cache/>
即可。至此配置完成。
在完成以上配置之后,对缓存进行测试
测试的核心代码
Java代码
SqlSession session = sqlSessionFactory.openSession(); List<User> allUsers = session.selectList("com.test.model.User.queryUserByName", "%test%", new RowBounds(1, 1)); session.commit(); List<User> allUsers3 = sqlSessionFactory.openSession().selectList("com.test.model.User.queryUserByName", "%test%", new RowBounds(1, 1));
理论上将,这种方式查询数据请求,在mybatis中肯定是可以直接从二级缓存中取数据的。
请看如下的图(网上找的,觉得还不错)。
其中CachingExecutor类的query方法
Java代码
public List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { if (ms != null) { Cache cache = ms.getCache(); if (cache != null) { flushCacheIfRequired(ms); cache.getReadWriteLock().readLock().lock(); try { if (ms.isUseCache() && resultHandler == null) { CacheKey key = createCacheKey(ms, parameterObject, rowBounds); final List cachedList = (List) cache.getObject(key); if (cachedList != null) { return cachedList; } else { List list = delegate.query(ms, parameterObject, rowBounds, resultHandler); tcm.putObject(cache, key, list); return list; } } else { return delegate.query(ms, parameterObject, rowBounds, resultHandler); } } finally { cache.getReadWriteLock().readLock().unlock(); } } } return delegate.query(ms, parameterObject, rowBounds, resultHandler); }
查询请求来的时候,会首先从MappedStatement中取出缓存实例Cache,若开启了二级缓存的,则先从二级缓存中查找数据,找到即直接返回结 果,若没有找到,则使用delegate(叫做代理业好,装饰器也好)所代理的查询(此处为BaseExecutor)来进行查询,代理的具体查询就不说 了,不是本文的重点。结合上图以及代码,可以看出tcm.putObject(cache, key, list);这句话是将查询处理的结果放入缓存,其中tcm是在CachingExecutor中定义的private TransactionalCacheManager tcm = new TransactionalCacheManager();
然后我们查看TransactionalCacheManager的putObject(cache, key, list)方法,如下
Java代码
public class TransactionalCacheManager { private Map<Cache, TransactionalCache> transactionalCaches = new HashMap<Cache, TransactionalCache>(); public void putObject(Cache cache, CacheKey key, Object value) { getTransactionalCache(cache).putObject(key, value); } }
继续查看TransactionalCache的源码,可以看到,在TransactionalCache的putObject(Object key, Object object)方法中,并不是直接将结果集合放入缓存中,而是加入到一个队列中,这个队列会再发起这次请求的SqlSession提交(commit)或 关闭(close)的时候,调用到TransactionalCache的commit方法,从而调用到内部类AddEntry的commit方法,将结 果集合存放到缓存中。
Java代码
public class TransactionalCache implements Cache { private Cache delegate; private Map<Object, AddEntry> entriesToAddOnCommit; public void putObject(Object key, Object object) { entriesToRemoveOnCommit.remove(key); entriesToAddOnCommit.put(key, new AddEntry(delegate, key, object)); } public void commit() { delegate.getReadWriteLock().writeLock().lock(); try { if (clearOnCommit) { delegate.clear(); } else { for (RemoveEntry entry : entriesToRemoveOnCommit.values()) { entry.commit(); } } for (AddEntry entry : entriesToAddOnCommit.values()) { entry.commit(); } reset(); } finally { delegate.getReadWriteLock().writeLock().unlock(); } } private static class AddEntry { private Cache cache; private Object key; private Object value; public AddEntry(Cache cache, Object key, Object value) { this.cache = cache; this.key = key; this.value = value; } public void commit() { cache.putObject(key, value); } } }