Mybatis的一级缓存,指的是SqlSession级别的缓存,默认开启;Mybatis的二级缓存,指的是SqlSessionFactory级别的缓存,需要配置。缓存是针对select来说的。
1、一级缓存
<configuration>
<settings>
<setting name="localCacheScope" value="SESSION|STATEMENT" />
</settings>
</configuration>
localCacheScope用于配置一级缓存的范围,默认值是SESSION,表示SqlSession范围;
如果配置为STATEMENT,则表示SqlSession范围内的一个查询范围,但它并不是一个Statement实例范围。
STATEMENT举例:查询Student对象发送一次sql查询,紧接着再发一次sql查询关联的Teacher对象,这个完整过程称之为一个查询。
一级缓存默认开启,且没有全局关闭的配置开关。
<select ... flushCache="false" useCache="true|false"/>
flushCache:同时影响了一级、二级缓存,flushCache=true,会导致清空本条sql(当前MappedStatement)的一级、二级缓存,注意是当前的,不影响其他的MappedStatement。
useCache:配置本条MappedStatement是否使用二级缓存,useCache=true,从二级缓存中获取,没有获取到,才从数据库中获取。
org.apache.ibatis.executor.CachingExecutor#query()方法源码:
Cache cache = ms.getCache();
if (cache != null) {
// flushCache作用于二级缓存
flushCacheIfRequired(ms);
// useCache作用于二级缓存
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, parameterObject, boundSql);
@SuppressWarnings("unchecked")
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
org.apache.ibatis.executor.BaseExecutor#query()方法源码:
if (queryStack == 0 && ms.isFlushCacheRequired()) {
// flushCache作用于一级缓存
clearLocalCache();
}
在执行update、insert、delete、flushCache="true"、commit、rollback、LocalCacheScope.STATEMENT等情况下,一级缓存就都会被清空。
缓存其实基本数据结构就是一个HashMap,缓存中是否存在缓存数据,依赖key的生成策略。
org.apache.ibatis.executor.BaseExecutor.createCacheKey()源码。
@Override
public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
CacheKey cacheKey = new CacheKey();
cacheKey.update(ms.getId());
cacheKey.update(Integer.valueOf(rowBounds.getOffset()));
cacheKey.update(Integer.valueOf(rowBounds.getLimit()));
cacheKey.update(boundSql.getSql());
for (int i = 0; i < parameterMappings.size(); i++) {
//...
cacheKey.update(value);
}
}
if (configuration.getEnvironment() != null) {
// issue #176
cacheKey.update(configuration.getEnvironment().getId());
}
return cacheKey;
}
id:com.mybatis3.mappers.TeacherMapper.findTeacherById
key的生成策略:id + offset + limit + sql + param value + environment id,这些值都相同,生成的key就相同。
2、二级缓存
<configuration>
<settings>
<setting name="cacheEnabled" value="true|false" />
</settings>
</configuration>
cacheEnabled=true表示二级缓存可用,但是要开启话,需要在Mapper.xml内配置。
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
二级缓存通过CachingExecutor来实现,原理是缓存里存在,就返回,没有就调用Executor delegate到数据库中查询。
org.apache.ibatis.executor.CachingExecutor.query()源码。
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds,
ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
Cache cache = ms.getCache();
if (cache != null) {
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, parameterObject, boundSql);
@SuppressWarnings("unchecked")
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
FIFO:First In First Out先进先出队列。
flushInterval="60000",间隔60秒清空缓存,这个间隔60秒,是被动触发的,而不是定时器轮询的。
size=512,表示队列最大512个长度,大于则移除队列最前面的元素,这里的长度指的是CacheKey的个数。
CacheKey的生成策略,和一级缓存相同,id + offset + limit + sql + param value + environment id。
readOnly="true",表示任何获取对象的操作,都将返回同一实例对象。如果readOnly="false",则每次返回该对象的拷贝对象,简单说就是序列化复制一份返回。
二级缓存有一个非常重要的空间划分策略:
namespace="com.mybatis3.mappers.TeacherMapper"
namespace="com.mybatis3.mappers.StudentMapper"
即,按照namespace划分,同一个namespace,同一个Cache空间,不同的namespace,不同的Cache空间。
每当执行insert、update、delete,flushCache=true时,二级缓存都会被清空。
版权提示:文章出自开源中国社区,若对文章感兴趣,可关注我的开源中国社区博客(http://my.oschina.net/zudajun)。(经过网络爬虫或转载的文章,经常丢失流程图、时序图,格式错乱等,还是看原版的比较好)
来源:oschina
链接:https://my.oschina.net/u/2727738/blog/747499