MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。缓存可以极大的提升查询效率。
MyBatis系统中默认定义了两级缓存, 一级 缓存和 二级缓存。
– 1、默认情况下,只有一级缓存(SqlSession级别的缓存,也称为本地缓存)开启,一级缓存默认实现类org.apache.ibatis.cache.impl.PerpetualCache。
– 2、二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
– 3、为了提高扩展性。MyBatis定义了缓存接口Cache,我们可以通过实现Cache接口来自定义二级缓存。

一级缓存

一级缓存是Local Cache,即本地缓存,默认作用域为SqlSesson级别,mybatis3.1之后, 可以配置本地缓存的作用域(SESSION|STATEMENT),在全局配置文件中可以设置localCacheScope。Mybatis默认的一级缓存默认是通过org.apache.ibatis.cache.impl.PerpetualCache来实现的,PerpetualCache内里有一个HashMap,用来存储本地缓存。

Map的CacheKey由方法的ID,RowBounds,SQL语句,参数,环境因素影响;Map的Value存放具体的结果对象。

格式:影响因子的HashCode1:影响因子的HashCode2:方法ID:offset:limit:SQL语句:参数:环境ID

-1623117942:1735139101:com.kancy.mapper.PersonMapper.selectPersonById:0:2147483647:select * from t_person where id = ? and last_name = ? and sex = ?:1:emma:0:test

public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
if (closed) {
throw new ExecutorException("Executor was closed.");
}
CacheKey cacheKey = new CacheKey();
cacheKey.update(ms.getId());
cacheKey.update(rowBounds.getOffset());
cacheKey.update(rowBounds.getLimit());
cacheKey.update(boundSql.getSql());
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();
// mimic DefaultParameterHandler logic
for (ParameterMapping parameterMapping : parameterMappings) {
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
String propertyName = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(propertyName)) {
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
cacheKey.update(value);
}
}
if (configuration.getEnvironment() != null) {
// issue #176
cacheKey.update(configuration.getEnvironment().getId());
}
return cacheKey;
}

从查询的源码可以看出,mybatis在查询前,先看是否需要清除缓存,再通过CacheKey从缓存中查找是否有对应的key,有则返回对象,无则从数据库中查找,再看一级缓存的作用域范围,是STATEMENT则清除缓存,否则将结果集放到缓存中。

public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
if (closed) {
throw new ExecutorException("Executor was closed.");
}
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
List<E> list;
try {
queryStack++;
list = resultHandler == null ? (List<E>)

localCache.getObject(key)

 : null;
if (list != null) {
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else
{
list =
queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}

} finally {
queryStack--;
}
if (queryStack == 0) {
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
// issue #601
deferredLoads.clear();
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
// issue #482
clearLocalCache();
}
}
return list;
}

一级缓存演示& & 失效情况

同一次会话期间只要查询过的数据都会保存在当前SqlSession的一个Map中
一级缓存失效的四种情况
– 1、不同的SqlSession对应不同的一级缓存
– 2、同一个SqlSession但是查询条件不同
– 3、同一个SqlSession两次查询期间执行了任何一次增删改操作
– 4、同一个SqlSession两次查询期间手动清空了缓存

注意:

– sql标签的flushCache属性查询默认flushCache=false;增删改insert|update|delete会修改数据,默认flushCache=true,会同时清空一级和二级缓存。
– sqlSession.clearCache():只是用来清除一级缓存,不会清除二级缓存。
– 当在某一个作用域 (一级缓存Session/二级缓存Namespaces) 进行了 C/U/D 操作后,默认该作用域下所有有select中的缓存将被clear。

二级缓存

最新文章

  1. 网页闯关游戏(riddle webgame)--SQL注入的潘多拉魔盒
  2. Xcode 重新下载项目配置文件
  3. python 练习 27
  4. [topcoder]IncreasingSubsequences
  5. GDB技巧整理
  6. 那些年被我坑过的Python——第十章Broker(rabbitMQ/redis)
  7. JS参数使用带参数的方法
  8. python语言学习1——初识python
  9. hdu5976贪心乘法逆元
  10. Android如何监听蓝牙耳机的按键事件(转)
  11. JS-类型转换
  12. Layout 不可思议(一)—— CSS 实现自适应的正方形卡片
  13. python-文件操作和集合
  14. SpringBoot操作数据库 2017.12.14
  15. 全文检索-Elasticsearch (四) elasticsearch.net 客户端
  16. Python 经典面试题汇总之框架篇
  17. squid3.5缓存代理实践记录
  18. BZOJ2127Happiness
  19. oracle 表空间,用户的创建及授权,表空间基本操作
  20. UBUNTU 16.04 安装AVD &quot;An error occurred while running &quot;android create avd

热门文章

  1. SIEM中心日志节点WEF搭建说明
  2. C# 防火墙操作之特定程序
  3. 控制 input 输入框不能输入中文,即不能在输入框中使用输入法
  4. 抓包工具之—charles碎言碎语
  5. 类Calendar
  6. 挣值管理(PV、EV、AC、SV、CV、SPI、CPI)
  7. Mac基本配置
  8. unity editor 折叠树
  9. 003/node.js--代理服务(解决跨域问题)
  10. Redis介绍及入门安装及使用