Mybatis的缓存模块位于org.apache.ibatis.cache。
Mybatis的缓存是基于Map实现的,从缓存里读写数据是缓存模块的核心功能。Mybatis的缓存还有很多额外的附加功能,如防止缓存击穿,设置缓存清除策略,日志功能等。这些附加功能可以以任意方式的组合附加到核心功能之上,而Mybatis采取的就是装饰器模式。
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新功能,是一种用于替代继承的技术,无需通过继承增加子类就能扩展对象的新功能。相比继承灵活性更强,扩展性更强。装饰器模式将功能切分成一个个独立的装饰器,在运行期可以根据需要动态的添加功能,进行自由的组合。当有新功能需要添加时,只需要增加新的装饰器实现类,通过组合方式添加,无需修改其他的代码。
组件Component:组件接口定义了全部组件类和装饰器的行为。
组件实现类ConcreteComponent:实现了Component接口,组件实现类就是被装饰器装饰的原始对象,新功能通过装饰器添加到该类的对象上。
装饰器抽象类Decorator:实现了Component接口的抽象类,在其中封装了一个Component对象,也就是被装饰的对象。
具体装饰器类ConcreteDecorator:该实现类要向被装饰的对象添加新功能。
IO中的输入输出流:BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("xxx")));
Servlet API中对request对象的装饰器
Mybatis的缓存模块
Cache:Cache接口是缓存模块的核心接口,定义了缓存的基本操作。
public interface Cache {
String getId();//缓存实现类的id
void putObject(Object key, Object value);//往缓存中添加数据,key一般是CacheKey对象
Object getObject(Object key);//根据指定的key从缓存获取数据
Object removeObject(Object key);//根据指定的key从缓存删除数据
void clear();//清空缓存
int getSize();//获取缓存的个数
ReadWriteLock getReadWriteLock();//获取读写锁
}
PerpetualCache:缓存的基础实现类,使用HashMap来实现缓存功能。
public class PerpetualCache implements Cache {
private final String id;
private Map
BlockingCache:阻塞版本的装饰器,保证只有一个线程到数据库去查指定key的数据。
public class BlockingCache implements Cache {
//阻塞的超时时长
private long timeout;
//被装饰的底层对象,一般是PerpetualCache
private final Cache delegate;
//锁对象集,粒度到key值
private final ConcurrentHashMap
其他装饰器也都类似,通过定义一个
private final Cache delegate;
复写Cache的方法,在执行delegate方法的之前,附加各自装饰器的功能。
Mybatis中通过CacheKey来封装缓存的key值。CacheKey由mapperStatment的id、分页信息、sql语句、实际参数构成。
private final int multiplier;//参与hash计算的乘数
private int hashcode;//CacheKey的hash值,在update函数中实时运算出来的
private long checksum;//校验和,hash值的和
private int count;//updateList的中元素个数
private List
public void update(Object object) {
//获取object的hash值
int baseHashCode = object == null ? 1 : ArrayUtil.hashCode(object);
//更新count、checksum以及hashcode的值
count++;
checksum += baseHashCode;
baseHashCode *= count;
hashcode = multiplier * hashcode + baseHashCode;
//将对象添加到updateList中
updateList.add(object);
}
@Override
public boolean equals(Object object) {
if (this == object) {//比较是不是同一个对象
return true;
}
if (!(object instanceof CacheKey)) {//是否类型相同
return false;
}
final CacheKey cacheKey = (CacheKey) object;
if (hashcode != cacheKey.hashcode) {//hashcode是否相同
return false;
}
if (checksum != cacheKey.checksum) {//checksum是否相同
return false;
}
if (count != cacheKey.count) {//count是否相同
return false;
}
//以上都不相同,才按顺序比较updateList中元素的hash值是否一致
for (int i = 0; i < updateList.size(); i++) {
Object thisObject = updateList.get(i);
Object thatObject = cacheKey.updateList.get(i);
if (!ArrayUtil.equals(thisObject, thatObject)) {
return false;
}
}
return true;
}