mybatis
一, myBatis一级缓存
解释:
1、什么缓存:
缓存就是数据的临时存储区,本质上来说是牺牲空间换取时间.例如cpu高速缓冲区,通过将数据暂存在高速缓冲区,避免了重复数据进行计算时,反复从内存中读取数据.
2、什么是myBatis一级缓存:当使用sqlSession从数据库查询数据时,mybatis会将查询到的数据暂存到内存中,当再次执行到相同的查询语句时,就可以直接从内存中获取到结果,而不需要再次获取数据库连接,从磁盘中获取.
需要注意的是,一级缓存的生命周期是在SqlSession中,也就是说,两个SqlSession对象之间是不会共享它们的一级缓存数据的.
上图的执行过程:
查询id为1的用户信息,从数据库获取数据.
将获取到的数据写入到一级缓存cache.
再次查询id为1的用户信息.
直接从一级缓存获取结果,不再查询数据库.
3、一级缓存什么时候会刷新:
sqlSession去执行commit操作(插入,更新,删除),则会清空SqlSession中的一级缓存.
SqlSession主动调用了clearCache()方法.
会话结束或者主动调用SqlSession.close()方法关闭会话.
4、一级缓存刷新:
关键方法:org.apache.ibatis.cache.impl.PerpetualCache#clear
可以发现cache是一个HashMap,因此刷新缓存也就是清空map.(cache.clear等价于map.clear)
5、myBatis是怎么判断两次查询是一致的:
上面提到当sqlSession再次查询id为1的用户信息时,会直接从一级缓存中获取数据,不会查询数据库.
那么myBatis到底时怎么保证两次相同的查询获取到同一份缓存呢.
现在我们知道cache是一个键值对结构的map.那么我们只能做到相同查询构建的key是相同的,那么是不是就可以保证不同查询语句之间不会互相干扰.
mybatis创建cacheKey的方法:
org.apache.ibatis.executor.BaseExecutor#createCacheKey
@Override public CacheKey createCacheKey(...) { if (closed) { throw new ExecutorException("Executor was closed."); } // 创建 CacheKey 对象 CacheKey cacheKey = new CacheKey(); // statementId cacheKey.update(ms.getId()); // 每页条数 cacheKey.update(rowBounds.getOffset()); // 页码 cacheKey.update(rowBounds.getLimit()); // 执行的sql cacheKey.update(boundSql.getSql()); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry(); // 入参. for (ParameterMapping parameterMapping : parameterMappings) { ...... cacheKey.update(value); } } // 环境id if (configuration.getEnvironment() != null) { // issue #176 cacheKey.update(configuration.getEnvironment().getId()); } return cacheKey; }
创建缓存key用到的参数:statementId,页码,分页条数,执行的sql,sql对应的入参,环境id.
通过这些条件就可以构成这样一个描述:执行开发环境StudyMapper.xml文件中id是findByCon的select user from user WHERE name=张三 LIMIT 1 ,10的查询语句.
通过这些条件可以很精确的定位到相同查询.
只要是环境,入参,分页条件等条件变化,cache.get(key)都不会再获取到之前缓存的值.
作者:xialu
链接:https://www.jianshu.com/p/ab4b15320470