mybatis一级缓存与二级缓存的原理
1.mybatis中的缓存是在mybatis框架中的Executor中来实现的,我们来看一下Executor的继承图

2.通过以上类图我们可以发现Executor接口下有两大实现类BaseExecutor与CachingExecutor
(1)BaseExecutor(用来存储我们的一级缓存)
@Override
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; //会先去localCache中去查找我们的数据
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;
}
(2)CachingExecutor(是装饰器模式的实现,用来查询我们的二级缓存)
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
Cache cache = ms.getCache(); //在MappedStatement中去获取二级缓存的类型。
if (cache != null) {
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, boundSql);
@SuppressWarnings("unchecked")
List<E> list = (List<E>) tcm.getObject(cache, key); //通过tcm来查询缓存,而tcm是CachingExecutor中的变量TransactionalCacheManager
if (list == null) {
list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); //delegate为CachingExecutor中保存的BaseExecutor的引用,若二级缓存不存在回去调用BaseExecutor的方法。
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
3.当我们开启二级缓存后Mybatis会使用CachingExecutor去装饰我们的BaseExecutor,所以会先查询二级缓存后再去查询一级缓存。
Configuration中的newExecutor方法
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) { //判断Executor的类型
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
if (cacheEnabled) { //如果二级缓存开启则使用CachingExecutor去装饰我们的executor;
executor = new CachingExecutor(executor);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
4.一级缓存与二级缓存的作用范围
(1)一级缓存(由于一级缓存是存在BaseExecutor中的,而Executor又作为创建SqlSession的参数,因此一级缓存具有和sqlsession一样的生命周期)
这是在SqlSessionFactory中调用openSession()中调用的方法
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
final Executor executor = configuration.newExecutor(tx, execType); //新建一个Executor作为参数传给DefaultSqlSession
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
(2)二级缓存(使用CachingExecutor来装饰)
//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(); //由此可见我们的二级缓存并不是储存在CachingExecutor中的,而是从MappedStatement中去获取。因此mybatis的二级缓存的生命周期为mapper级别的
if (cache != null) {
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, 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);
}
mybatis一级缓存与二级缓存的原理的更多相关文章
- Mybatis 一级缓存和二级缓存原理区别 (图文详解)
Java面试经常问到Mybatis一级缓存和二级缓存,今天就给大家重点详解Mybatis一级缓存和二级缓存原理与区别@mikechen Mybatis缓存 缓存就是内存中的数据,常常来自对数据库查询结 ...
- MyBatis 延迟加载,一级缓存,二级缓存设置
什么是延迟加载 resultMap中的association和collection标签具有延迟加载的功能. 延迟加载的意思是说,在关联查询时,利用延迟加载,先加载主信息.使用关联信息时再去加载关联信息 ...
- 9.Mybatis一级缓存和二级缓存
所谓的缓存呢?其实原理很简单,就是在保证你查询的数据是正确的情况下,没有去查数据库,而是直接查找的内存,这样做有利于缓解数据库的压力,提高数据库的性能,Mybatis中有提供一级缓存和二级缓存. 学习 ...
- 八 mybatis查询缓存(一级缓存,二级缓存)和ehcache整合
1 查询缓存 1.1 什么是查询缓存 mybatis提供查询缓存,用于减轻数据压力,提高数据库性能. mybaits提供一级缓存,和二级缓存.
- mybatis 详解(九)------ 一级缓存、二级缓存
上一章节,我们讲解了通过mybatis的懒加载来提高查询效率,那么除了懒加载,还有什么方法能提高查询效率呢?这就是我们本章讲的缓存. mybatis 为我们提供了一级缓存和二级缓存,可以通过下图来理解 ...
- Mybatis第八篇【一级缓存、二级缓存、与ehcache整合】
Mybatis缓存 缓存的意义 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题. myba ...
- MyBatis 一级缓存,二级缓存,延迟加载设置
1 什么是延迟加载 resultMap中的association和collection标签具有延迟加载的功能. 延迟加载的意思是说,在关联查询时,利用延迟加载,先加载主信息.使用关联信息时再 ...
- mybatis的延迟加载、一级缓存、二级缓存
mybatis的延迟加载.一级缓存.二级缓存 mybatis是什么? mybatis是一个持久层框架,是apache下的开源项目,前身是itbatis,是一个不完全的ORM框架,mybatis提供输入 ...
- 深入理解MyBatis中的一级缓存与二级缓存
http://blog.csdn.net/weixin_36380516/article/details/73194758 先说缓存,合理使用缓存是优化中最常见的,将从数据库中查询出来的数据放入缓 ...
随机推荐
- 和大于S的最小子数组 · Minimum Size Subarray Sum
[抄题]: 给定一个由 n 个正整数组成的数组和一个正整数 s ,请找出该数组中满足其和 ≥ s 的最小长度子数组.如果无解,则返回 -1. 给定数组 [2,3,1,2,4,3] 和 s = 7, 子 ...
- sort_contours_xld算子的几种排序方式研究
算子sort_contours_xld算子有5种排序方式,即: 'upper_left': The position is determined by the upper left corner of ...
- [Training Video - 6] [File Reading] [Groovy] Reading Properties file
Reading Properties file : Properties prop = new Properties() def path = "D:\\SoapUIStudy\\appli ...
- openGL中的原理理解1---一个视图需要支持OGL需要配置,GLenbalView的理解
OpenGL的绘图机制是 OpenGL的绘图方式与Windows一般的绘图方式是不同的,主要区别如下: (1)Windows采用的是GDI(Graphy Device Interface 图形设备接口 ...
- centos 虚拟机中修改屏幕分辨率
1.$ vi /boot/grub/grub.conf(路径可能会不一样,也可以是 /etc/grub.conf),打开grub.conf文件 2.我们修改分辨率,需要在kernel那行加入 vga= ...
- struts中request传递中文乱码问题
系统本来是好好地,这两天升级后,各种问题不断,总而言之,一句话,心惊胆战. 今天,搜索任何中文,都是有乱码,在action中转码就ok了.公司系统那么多action,都转码,要累死吧.配置的过滤器都不 ...
- docker 版本变化及说明
Docker从1.13.x版本开始,版本分为企业版EE和社区版CE,版本号也改为按照时间线来发布,比如17.03就是2017年3月,有点类似于ubuntu的版本发布方式. 企业版自然会提供一些额外的服 ...
- pycharm设置及激活码
电脑上装了python2.7和python3.6两个版本(之前用的都是python3,因为要学习机器学习和深度学习了,机器学习的有些模块还没有更新到python3,于是乎又装了python2)为了能在 ...
- 修改TFS附件大小的限制
在TFS服务器使用浏览器上打开如下地址:http://localhost:8080/tfs/<CollectionName>/WorkItemTracking/v1.0/Configura ...
- python的print()输出
1.普通的输出: print(str)#str是任意一个字符串,数字··· 2.格式化输出: print('1,2,%s,%d'%('asd',4)) 1,2,asd,4 与C语言有点类似 3.其它: ...