缓存概述
java
在mybatis中,缓存的功能由根接口Cache(org.apache.ibatis.cache.Cache)定义。整个体系采用装饰器设计模式,数据存储和缓存的基本功能由PerpetualCache(org.apache.ibatis.cache.impl.PerpetualCache)永久缓存实现,而后经过一系列的装饰器来对PerpetualCache永久缓存进行缓存策略等方便的控制。以下图:算法
用于装饰PerpetualCache的标准装饰器共有8个(所有在org.apache.ibatis.cache.decorators包中):apache
1.FifoCache:先进先出算法,缓存回收策略设计模式
2.LoggingCache:输出缓存命中的日志信息缓存
3.LruCache:最近最少使用算法,缓存回收策略mybatis
4.ScheduledCache:调度缓存,负责定时清空缓存多线程
5.SerializedCache:缓存序列化和反序列化存储并发
6.SoftCache:基于软引用实现的缓存管理策略app
7.SynchronizedCache:同步的缓存装饰器,用于防止多线程并发访问框架
8.WeakCache:基于弱引用实现的缓存管理策略
另外,还有一个特殊的装饰器TransactionalCache:事务性的缓存
正如大多数持久层框架同样,mybatis缓存一样分为一级缓存和二级缓存
一级缓存,又叫本地缓存,是PerpetualCache类型的永久缓存,保存在执行器中(BaseExecutor),而执行器又在SqlSession(DefaultSqlSession)中,因此一级缓存的生命周期与SqlSession是相同的。
二级缓存,又叫自定义缓存,实现了Cache接口的类均可以做为二级缓存,因此可配置如encache等的第三方缓存。二级缓存以namespace名称空间为其惟一标识,被保存在Configuration核心配置对象中。以下:
public class Configuration { // ... protected final Map<String, Cache> caches = new StrictMap<Cache>("Caches collection"); // ... }
每次构建SqlSessionFactory对象时都会建立新的Configuration对象,所以,二级缓存的生命周期与SqlSessionFactory是相同的。在建立每一个MapperedStatement对象时,都会根据其所属的namespace名称空间,给其分配Cache缓存对象。
二级缓存对象的默认类型为PerpetualCache,若是配置的缓存是默认类型,则mybatis会根据配置自动追加一系列装饰器。
Cache对象之间的引用顺序为:
SynchronizedCache-->LoggingCache-->SerializedCache-->ScheduledCache-->LruCache-->PerpetualCache
全部的缓存对象的操做与维护都是由Executor器执行来完成的,一级缓存由BaseExecutor(包含SimpleExecutor、ReuseExecutor、BatchExecutor三个子类)负责维护,二级缓存由CachingExecutor负责维护。所以须要注意的是:配置了二级缓存不表明mybatis就会使用二级缓存,还须要确保在建立SqlSession的过程当中,mybatis建立是CachingExecutor类型的执行器。
Executor中对Cache的具体操做逻辑,请点击mybatis核心组件详解——Executor
源码解读:
Cache接口:
package org.apache.ibatis.cache; import java.util.concurrent.locks.ReadWriteLock; /** * 缓存接口 * 给缓存供应商的SPI(Service Provider Interface) * 一个Cache的实例将为名称空间被建立 * Cache接口的实现类必须有一个具备String类型参数的构造方法,用于接收Cache对象的id,做为其惟一标识 * * mybatis将以namespace做为id调用这个构造函数建立对象 * * @author Administrator * */ public interface Cache { /** * 获取缓存对象的惟一标识 * @return */ String getId(); /** * 保存key/value到缓存对象中 * key能够是任何对象,但通常是CacheKey对象 * value是查询结果,为List类型 * @param key * @param value */ void putObject(Object key, Object value); /** * 从缓存对象中获取key对应的value * @param key * @return */ Object getObject(Object key); /** * 可选的方法,没有被核心框架调用,移除key对应的value * @param key * @return */ Object removeObject(Object key); /** * 清空缓存 */ void clear(); /** * 获取缓存对象中存储的键/值对的数量 * 可选的方法,没有被框架核心调用 */ int getSize(); /** * 获取读写锁 * 可选的方法,从3.2.6起这个方法再也不被框架核心调用 * 任何须要的锁,都必须由缓存供应商提供 * * @return A ReadWriteLock */ ReadWriteLock getReadWriteLock(); }
PerpetualCache永久缓存:
package org.apache.ibatis.cache.impl; import java.util.HashMap; import java.util.Map; import java.util.concurrent.locks.ReadWriteLock; import org.apache.ibatis.cache.Cache; import org.apache.ibatis.cache.CacheException; /** * 永久缓存 Cache接口实现类 * Cache接口只有这惟一一个基础实现,其余实现类全都是装饰模式持有另外一个缓存对象 * * @author Administrator * */ public class PerpetualCache implements Cache { // 缓存对象的惟一标识 private String id; // 对象内部维护的HashMap private Map<Object, Object> cache = new HashMap<Object, Object>(); public PerpetualCache(String id) { this.id = id; } public String getId() { return id; } public int getSize() { return cache.size(); } public void putObject(Object key, Object value) { cache.put(key, value); } public Object getObject(Object key) { return cache.get(key); } public Object removeObject(Object key) { return cache.remove(key); } public void clear() { cache.clear(); } public ReadWriteLock getReadWriteLock() { return null; } public boolean equals(Object o) { if (getId() == null) throw new CacheException("Cache instances require an ID."); if (this == o) return true; if (!(o instanceof Cache)) return false; Cache otherCache = (Cache) o; return getId().equals(otherCache.getId()); } public int hashCode() { if (getId() == null) throw new CacheException("Cache instances require an ID."); return getId().hashCode(); } }
在mybatis中,PerpetualCache是惟一的Cache接口的基础实现。它内部维护一个HashMap,全部的缓存操做,其实都是对这个HashMap的操做。
其余Cache接口的实现类所有为装饰器,源码详解请点击mybatis缓存机制详解(二)——缓存装饰器