MyBatis二级缓存巧妙使用装饰器模式与builder模式
mybatis在查询数据时使用一级缓存和二级缓存来提交查询效率,并减少数据库压力。
- 一级缓存也称为本地缓存,是默认开启的,它的生效范围为sqlSession,在实际的生产项目中,由于数据库连接是从连接池中获取,几乎每次使用的session都不同,因此很少能使用到一级缓存。
- 二级缓存也称为全书缓存,它的生效范围在一个namespace中,如果需要使用二级缓存需要我们手动开启,第一步:在mybatis全书配置文件加入setting设置
<setting name="cacheEnabled" value="true"></setting>
,第二步:在mapper.xml配置文件中加入cache标签<cache type="org.mybatis.caches.redis.RedisCache"></cache>
,如果不需要自定义缓存,则不用指定type,此时会使用默认的缓存实现类org.apache.ibatis.cache.impl.PerpetualCache来实现二级缓存,它的底层就是用HashMap来实现的。
在实际开发中,二级缓存还是用的比较多的,使用mybatis结合redis实现二级缓存非常方便,它也能适用于分布式场景。在阅读mybatis源码过程中,发现mybatis生成缓存类的时候,使用了装饰器模式和builder模式,结合的非常巧妙,故写此文章与各位分享。装饰器模式和builder模式不是本次主要讨论的主题,只作简要概述。
装饰器模式主要用于增强对象功能,
装饰器模式的核心在于给原始对象加装饰器是在构造方法中进行的,而原始对象是作为代理存在的,被内层装饰器装饰后的对象又作为外层装饰器的代理,使用时,外层装饰器执行方法时,核心方法由代理对象完成,同时可以加上装饰器的特有功能,例如日志记录。下面来看看mybatis中缓存类是如何使用装饰器模式的:mybatis中的缓存装饰器有很多,分别实现不同的功能,而它提供的缓存实现类只有一个即PerpetualCache,它也是我们前面所提到的默认缓存实现类,每个装饰器都实现了Cache接口
public interface Cache {
String getId();
void putObject(Object key, Object value);
Object getObject(Object key);
Object removeObject(Object key);
void clear();
int getSize();
ReadWriteLock getReadWriteLock();
}
这个接口规定了缓存类需要有的功能,缓存实现类PerpetualCache以及装饰器decorators都实现了这个接口,这个就规定了它们的类型都是一个Cache。前面说过 ***PerpetualCache***底层是由一个HashMap实现的,我们来看它的代码
public class PerpetualCache implements Cache {
private final String id;
private Map<Object, Object> cache = new HashMap<>();//存储缓存数据的容器
public PerpetualCache(String id) {
this.id = id;
}
@Override
public String getId() {
return id;
}
@Override
public int getSize() {
return cache.size();
}
@Override
public void putObject(Object key, Object value) {
cache.put(key, value);
}
@Override
public Object getObject(Object key) {
return cache.get(key);
}
@Override
public Object removeObject(Object key) {
return cache.remove(key);
}
@Override
public void clear() {
cache.clear();
}
@Override
public ReadWriteLock getReadWriteLock() {
return null;
}
@Override
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());
}
@Override
public int hashCode() {
if (getId() == null) {
throw new CacheException("Cache instances require an ID.");
}
return getId().hashCode();
}
}
它的功能比较单一,但是用于二级缓存也足够了。于是mybatis在此基础上,拓展了很多功能,都是装饰器实现,我们随便看一个org.apache.ibatis.cache.decorator