MyBatis的一二级缓存
一级缓存
一级缓存默认是开启的,生命周期和SqlSession相同。一个会话中每次执行一个查询操作时,会先查询二级缓存,如果二级缓存没查到或者二级缓存未开启就会从一级缓存中查询,如果一级缓存也未查到就从数据库中查询
一级缓存使用条件
- 必须是相同的SQL语句
- 必须是相同的参数
- 必须是同一个会话
- 必须是同一个namespace即相同的mapper接口
- 必须是同一个mapper接口中的同一个方法
- 查询之前没有增删改操作(不管操作是否成功,只要进行了增删改操作就会清空一级缓存)
- 查询之前没有执行sqlSession.clearCache()方法
二级缓存
二级缓存需要我们手动开启,生命周期和SqlSessionFactory相同。可以适用于多个session之间共享数据
开启二级缓存
在mapper接口上面写@CacheNamespace注解,需要注意的是如果采用了注解方式,那么写SQL语句也需要使用注解,否则二级缓存不会生效
@CacheNamespace(
implementation = PerpetualCache.class, // 缓存实现 Cache接口 实现类
eviction = LruCache.class,// 缓存算法
flushInterval = 60000, // 刷新间隔时间 毫秒
size = 1024, // 最大缓存引用对象
readWrite = true, // 是否可写
blocking = false // 是否阻塞
)
在xxxMapper.xml文件中定义cache标签
二级缓存使用条件
- 当会话提交或者关闭时才会填充数据到二级缓存中
- 必须是在同一个命名空间下
- 必须是相同的statment,即同一个mapper接口的同一个方法
- 必须是相同的SQL语句和参数
- 如果readWrite=true ,实体类必须实现Serializable 接口
二级缓存清空条件
- 任何一种增删改操作 都会清空整个namespace 中的缓存
- 只有修改会话提交之后 才会执行清空操作
调用链
顶层api调用
PersonMapper mapper = session.getMapper(PersonMapper.class);
Person person1 = mapper.selectPersonById(1);
不管是调用select方法还是update方法,都会进入DefaultSqlSession类中,并调用对应方法
/*
DefaultSqlSession > selectList() getMappedStatement(statement) 方法,statement即为namespace + selectId。通过configuration获取mapperedStatement,MapperedStatement封装了id、sqlSource、resultMap、paramType等。 通过executor调用下一层的executor执行器执行
*/ @Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
然后进入CacheExecutor中尝试获取二级缓存
/*
CacheExecutor > query() 获取二级缓存的key值
*/
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { BoundSql boundSql = ms.getBoundSql(parameterObject);
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
/*
CacheExecutor > 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) { //如果cache为空,说明未开启二级缓存
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.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
//将值存入二级缓存中
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
//如果没有获取二级缓存,就尝试去获取一级缓存
return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
- 如果二级缓存没有开启或者未从二级缓存中获取到值,就走一级缓存
/*
BaseExecutor > query()
*/
......
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--;
} ......从缓存中获取值
不管是二级缓存,还是一级缓存都是从perpetualCache类中的HashMap中进行取值和赋值等操作
/*
PerpetualCache > getObject()
*/ @Override
public Object getObject(Object key) {
return cache.get(key);
}
MyBatis的一二级缓存的更多相关文章
- 认识Mybatis的一二级缓存
认识Mybatis的一二级缓存 一次完整的数据库请求,首先根据配置文件生成SqlSessionFactory,再通过SqlSessionFactory开启一次SqlSession,在每一个SqlSes ...
- java架构之路-(源码)mybatis的一二级缓存问题
上次博客我们说了mybatis的基本使用,我们还捎带提到一下Mapper.xml中的select标签的useCache属性,这个就是设置是否存入二级缓存的. 回到我们正题,经常使用mybatis的小伙 ...
- 【MyBatis源码解析】MyBatis一二级缓存
MyBatis缓存 我们知道,频繁的数据库操作是非常耗费性能的(主要是因为对于DB而言,数据是持久化在磁盘中的,因此查询操作需要通过IO,IO操作速度相比内存操作速度慢了好几个量级),尤其是对于一些相 ...
- mybatis 源码分析(四)一二级缓存分析
本篇博客主要讲了 mybatis 一二级缓存的构成,以及一些容易出错地方的示例分析: 一.mybatis 缓存体系 mybatis 的一二级缓存体系大致如下: 首先当一二级缓存同时开启的时候,首先命中 ...
- Mybatis学习(6)动态加载、一二级缓存
一.动态加载: resultMap可以实现高级映射(使用association.collection实现一对一及一对多映射),association.collection具备延迟加载功能. 需求: 如 ...
- Mybatis一二级缓存的理解
频繁的数据库操作是非常耗费性能的(主要是因为对于DB而言,数据是持久化在磁盘中的,因此查询操作需要通过IO,IO操作速度相比内存操作速度慢了好几个量级),尤其是对于一些相同的查询语句,完全可以 ...
- [原创]关于mybatis中一级缓存和二级缓存的简单介绍
关于mybatis中一级缓存和二级缓存的简单介绍 mybatis的一级缓存: MyBatis会在表示会话的SqlSession对象中建立一个简单的缓存,将每次查询到的结果结果缓存起来,当下次查询的时候 ...
- MyBatis学习--查询缓存
简介 以前在使用Hibernate的时候知道其有一级缓存和二级缓存,限制ORM框架的发展都是互相吸收其他框架的优点,在Hibernate中也有一级缓存和二级缓存,用于减轻数据压力,提高数据库性能. m ...
- Mybatis的二级缓存配置
一个项目中肯定会存在很多共用的查询数据,对于这一部分的数据,没必要每一个用户访问时都去查询数据库,因此配置二级缓存将是非常必要的. Mybatis的二级缓存配置相当容易,要开启二级缓存,只需要在你的 ...
随机推荐
- Layui treeSelect 回写与对应选中
今天遇到个问题就是Layui treeSelect 的回写与特定选中,网络上居然没啥资料,有的也是不全的,于是花了点时间处理好了,这里写一下,方便以后有遇到的朋友借鉴. 一.父页面 二.Form编辑框 ...
- python的各种库的用法
scipy.io 用于输入和输出数据的操作,可操作matlab的.mat文件. (1)加载.mat文件的数据 import scipy.io as sci data_dir = sci.loadmat ...
- 使用ML.NET模型生成器来完成图片性别识别
什么是ML.NET? ML.NET 使你能够在联机或脱机场景中将机器学习添加到 .NET 应用程序中. 借助此功能,可以使用应用程序的可用数据进行自动预测. 机器学习应用程序利用数据中的模式来进行预测 ...
- C#连接Access
连接数据库 string oleCon = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source= " + Application.Sta ...
- 什么PO模式?
PO模式PO是Page Object的缩写,PO模式是自动化测试项目开发实践的最佳设计模式之一.核心思想是通过对界面元素的封装减少冗余代码,同时在后期维护中,若元素定位发生变化, 只需要调整页面元素封 ...
- 4G DTU模块和串口设备连接的方式
首先说下解决思路: 由于考虑到串口开发很麻烦,所以后来买了一个4g模块的dtu. 所以最后的解决方案是,plc串口设备与dtu相连,由于dtu是透传模式,使用java与4g模块进行通信就完事了. 虽然 ...
- 正式班D21
2020.11.03星期二 正式班D21 目录 11.5 源码包 11.5.1 预先安装编译安装依赖的库 11.5.2 官网下载源码包 11.5.3 解压.编译.编译安装 11.5 源码包 11.5. ...
- 微服务通信之ribbon实现原理
前言 上一篇我们知道了feign调用实现负载均衡是通过集成ribbon实现的.也较为详细的了解到了集成的过程.现在我们看一下ribbo是如何实现负载均衡的.写到这里我尚未去阅读源代码,我在这里盲猜一下 ...
- LRU算法详解
一.什么是 LRU 算法 就是一种缓存淘汰策略. 计算机的缓存容量有限,如果缓存满了就要删除一些内容,给新内容腾位置.但问题是,删除哪些内容呢?我们肯定希望删掉哪些没什么用的缓存,而把有用的数据继续留 ...
- IDEA 搭建 Spark 源码 (Ubuntu)
版本:Spark 2.4.3/JDK 1.8/Scala 2.11.0 1.选择Spark版本.压缩包下载. 2.IDEA中左下角Terminal下输入: mvn -DskipTests clean ...