Mybatis缓存实现原理
Mybatis缓存
mybatis提供了对缓存的支持,分为一级缓存和二级缓存,可以通过下图来理解:
①、一级缓存是SqlSession级别的缓存,默认开启。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。
②、二级缓存是mapper级别的缓存,基于mapper文件的namespace,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
一级缓存
⼀级缓存到底是什么?⼀级缓存什么时候被创建、⼀级缓存的⼯作流程是怎样的?
在执行openSession
的时候,会创建Executor
对象,根据执行器的类型ExecutorType
选择的是SIMPLE
类型,
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 = new BatchExecutor(this, transaction);} else if (ExecutorType.REUSE == executorType) {executor = new ReuseExecutor(this, transaction);} else {// 创建简单执行器executor = new SimpleExecutor(this, transaction);}if (cacheEnabled) {// 创建缓存执行器// 处理二级缓存的地方装饰器对象,在执行的查询的时候,MyBatis会先去二级缓存中去查找executor = new CachingExecutor(executor);}executor = (Executor) interceptorChain.pluginAll(executor);return executor;}
然后创建的SimpleExecutor
对象,在这个对象创建的过程中,是调用的父类BaseExecutor
对象,在父类实例化的过程中,创建PerpetualCache
缓存对象。一级缓存其实就是本地存放的⼀个map对象。
protected BaseExecutor(Configuration configuration, Transaction transaction) {this.transaction = transaction;// 延迟加载this.deferredLoads = new ConcurrentLinkedQueue<>();// 创建本地缓存,即一级缓存this.localCache = new PerpetualCache("LocalCache");// 处理存储过程缓存,这里不讨论存储过程this.localOutputParameterCache = new PerpetualCache("LocalOutputParameterCache");this.closed = false;this.configuration = configuration;this.wrapper = this;}
SqlSession内部调用BaseExecutor查询,核心代码如下。
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {// 去掉了不必要、延时加载等代码。List<E> list;// 查询缓存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);}return list;}
执行更新操作时,先清空缓存,再执行更新操作。
public int update(MappedStatement ms, Object parameter) throws SQLException {// ...clearLocalCache();return doUpdate(ms, parameter);
}
二级缓存
需要在配置文件中显式配置启动二级缓存。
配置
核心配置文件:mybatis-config.xml
<settings><!--全局缓存开关,默认开启--><setting name="cacheEnabled " value="true"/></settings>
mapper.xml
<!--开启⼆级缓存,mapper.xml中所有标签默认才使用二级缓存-->
<cache></cache>
开启了⼆级缓存后,还需要将要缓存的pojo实现Serializable接⼝,为了将缓存数据取出执⾏反序列化操作,因为⼆级缓存数据存储介质多种多样,不⼀定只存在内存中,有可能存在硬盘中,如果我们要再取这个缓存的话,就需要反序列化了。
flushCache和useCache属性
在statement中设置useCache=false可以禁⽤当前select语句的⼆级缓存。
flushCache在查询时默认false,在更新操作时默认true,清空二级缓存。
<select id="selectUserByUserId" flushCache="true" useCache="false" resultType="User" parameterType="int">select * from user where id=#{id}
</select>
⼀般下执⾏完commit操作都需要刷新缓存,默认即可。
原理
原理与一级缓存基本相同
多个sqlsession
对同一个Mapper进行查询操作时是可以共享这个namespace
中的缓存数据,但是当我们去当前这个mapper
中的进行增、删、改或者commit
的时候,同样是会清空缓存。
原理
如上。CachingExecutor
对象是处理二级缓存的地方装饰器对象,在执行的查询的时候,MyBatis会先去二级缓存中去查找
二级缓存Cache是从MappedStatement中获取到的,而MappedStatement又和每一个<insert>、<delete>、<update>、<select>
绑定并在MyBatis启动的时候存入Configuration中:
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事务缓存对象中tcm.putObject(cache, key, list); // issue #578 and #116}return list;}}// 再查询一级缓存或数据库。return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
更新操作
public int update(MappedStatement ms, Object parameterObject) throws SQLException {// 必要的时候刷新缓存。内部将commit时清空设置成了true。flushCacheIfRequired(ms);// 执行更新操作return delegate.update(ms, parameterObject);
}
update()
方法中只有清空一级缓存的缓存的方法,而真正清空缓存的方法是在commit
方法中,所以二级缓存的使用一定注意提交事务。二级缓存是委托了tcm
对象管理管理缓存的。
使用Redis实现二级缓存
MyBatis的缓存是和整个应用运行在同一个JVM中的,共享同一块堆内存,但是无法解决数据量大和分布式缓存两个问题,此时需要使用外部缓存(Redis)代替本地Map缓存PerpetualCache。
相关配置
mapper.xml
<cache type="org.mybatis.caches.redis.RedisCache" />
添加redis.properties,配置Redis信息。
public final class RedisCache implements Cache {private final ReadWriteLock readWriteLock = new DummyReadWriteLock();private String id;private static JedisPool pool;public RedisCache(final String id) {this.id = id;RedisConfig redisConfig = RedisConfigurationBuilder.getInstance().parseConfiguration();pool = new JedisPool(redisConfig, redisConfig.getHost(), redisConfig.getPort(),redisConfig.getConnectionTimeout(), redisConfig.getSoTimeout(), redisConfig.getPassword(),redisConfig.getDatabase(), redisConfig.getClientName());}
}
RedisCache实现Cache接口,使用jedis实现。数据存取采用hash结构。
Mybatis缓存实现原理相关推荐
- 五分钟,带你彻底掌握 MyBatis缓存 工作原理
作者:双子孤狼 blog.csdn.net/zwx900102/article/details/108696005 前言 在计算机的世界中,缓存无处不在,操作系统有操作系统的缓存,数据库也会有数据库的 ...
- mybatis 二级缓存失效_给我五分钟,带你彻底掌握MyBatis的缓存工作原理
前言 在计算机的世界中,缓存无处不在,操作系统有操作系统的缓存,数据库也会有数据库的缓存,各种中间件如Redis也是用来充当缓存的作用,编程语言中又可以利用内存来作为缓存.自然的,作为一款优秀的ORM ...
- 给我五分钟,带你彻底掌握 MyBatis 缓存的工作原理
前言 在计算机的世界中,缓存无处不在,操作系统有操作系统的缓存,数据库也会有数据库的缓存,各种中间件如Redis也是用来充当缓存的作用,编程语言中又可以利用内存来作为缓存.自然的,作为一款优秀的ORM ...
- Mybatis——缓存原理和分析
摘要 主要是分析的一下Mybatis的一级缓存和二级缓存的原理和源码的操作.每一次在和数据库进行会话的过程中,MyBatis 都会创建一个SqlSession对象.同一次会话期间,只要是查询过的数据, ...
- MyBatis(三)MyBatis缓存和工作原理
MyBatis缓存 MyBatis提供了一级缓存和二级缓存,并且预留了集成第三方缓存的接口. 从上面MyBatis的包结构可以很容易看出跟缓存相关的类都在cache的package里,其底层是一个Ca ...
- 实际测试例子+源码分析的方式解剖MyBatis缓存的概念
前言: 前方高能! 本文内容有点多,通过实际测试例子+源码分析的方式解剖MyBatis缓存的概念,对这方面有兴趣的小伙伴请继续看下去~ 欢迎工作一到五年的Java工程师朋友们加入Java架构开发:79 ...
- mybatis 传入id_想深入理解MyBatis架构及原理实例分析 把握这些就够了
前言 MyBatis是目前非常流行的ORM框架,它的功能很强大,然而其实现却比较简单.优雅.本文主要讲述MyBatis的架构设计思路,并且讨论MyBatis的几个核心部件,然后结合一个select查询 ...
- mybatis的工作原理
MyBatis 的工作原理 在学习 MyBatis 程序之前,读者需要了解一下 MyBatis 工作原理,以便于理解程序.MyBatis 的工作原理如图 2 所示. 下面对图 2 中的每步流程进行说明 ...
- MyBatis缓存通俗易懂
1.1 mybatis缓存介绍 如下图,是mybatis一级缓存和二级缓存的区别图解: Mybatis一级缓存的作用域是同一个SqlSession,在同一个sqlSession中两次执行相同的 ...
- 缓存在哪里_什么是MyBatis缓存技术
MyBatis缓存 引言 在一个Web项目中,查询数据库中的操作算是一个非常常用的操作,但是有些数据会被经常性的查询,而每一次都去数据库中查询这些重复的数据,会很消耗数据库的资源,同时使得查询效率也很 ...
最新文章
- 文件时间信息在测试中的应用
- Java语言中的生僻知识
- c++美发店管理系统设计_美发店如何打造会员管理系统?掌柜智囊—收银机必不可少...
- 最简单的基于FFmpeg的移动端例子:IOS 推流器
- CodeForces - 1457E New Game Plus!(贪心)
- pyspider 安装 和 快速开始
- excel表格不够怎么添加_Excel表格水印,你以前好象添加错了!
- php李捷,【问题解答】蝶泳手外划的作用
- 有向图的传递闭包实现三种实现(Warshall+DFS+BFS)
- js排序算法详解-基数排序
- 2022 chrome离线下载包
- windows操作系统下新建txt文件快捷键
- [扩欧]JZOJ 5855 吃蛋糕
- 小项目一:使用fping统计网络中主机的网络连通情况
- Unity 制作萌系live2d桌宠:屏幕自适应+交互
- 蓝牙耳机哪个品牌比较好?盘点四款好用的蓝牙耳机
- sql loader导出数据和导入数据(sqlldr)
- Python基础——魔法方法(一)
- ERROR: Failed building wheel for pillow and ERROR: running bdist_wheel问题解决
- 白话空间统计之:空间异质性