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缓存实现原理相关推荐

  1. 五分钟,带你彻底掌握 MyBatis缓存 工作原理

    作者:双子孤狼 blog.csdn.net/zwx900102/article/details/108696005 前言 在计算机的世界中,缓存无处不在,操作系统有操作系统的缓存,数据库也会有数据库的 ...

  2. mybatis 二级缓存失效_给我五分钟,带你彻底掌握MyBatis的缓存工作原理

    前言 在计算机的世界中,缓存无处不在,操作系统有操作系统的缓存,数据库也会有数据库的缓存,各种中间件如Redis也是用来充当缓存的作用,编程语言中又可以利用内存来作为缓存.自然的,作为一款优秀的ORM ...

  3. 给我五分钟,带你彻底掌握 MyBatis 缓存的工作原理

    前言 在计算机的世界中,缓存无处不在,操作系统有操作系统的缓存,数据库也会有数据库的缓存,各种中间件如Redis也是用来充当缓存的作用,编程语言中又可以利用内存来作为缓存.自然的,作为一款优秀的ORM ...

  4. Mybatis——缓存原理和分析

    摘要 主要是分析的一下Mybatis的一级缓存和二级缓存的原理和源码的操作.每一次在和数据库进行会话的过程中,MyBatis 都会创建一个SqlSession对象.同一次会话期间,只要是查询过的数据, ...

  5. MyBatis(三)MyBatis缓存和工作原理

    MyBatis缓存 MyBatis提供了一级缓存和二级缓存,并且预留了集成第三方缓存的接口. 从上面MyBatis的包结构可以很容易看出跟缓存相关的类都在cache的package里,其底层是一个Ca ...

  6. 实际测试例子+源码分析的方式解剖MyBatis缓存的概念

    前言: 前方高能! 本文内容有点多,通过实际测试例子+源码分析的方式解剖MyBatis缓存的概念,对这方面有兴趣的小伙伴请继续看下去~ 欢迎工作一到五年的Java工程师朋友们加入Java架构开发:79 ...

  7. mybatis 传入id_想深入理解MyBatis架构及原理实例分析 把握这些就够了

    前言 MyBatis是目前非常流行的ORM框架,它的功能很强大,然而其实现却比较简单.优雅.本文主要讲述MyBatis的架构设计思路,并且讨论MyBatis的几个核心部件,然后结合一个select查询 ...

  8. mybatis的工作原理

    MyBatis 的工作原理 在学习 MyBatis 程序之前,读者需要了解一下 MyBatis 工作原理,以便于理解程序.MyBatis 的工作原理如图 2 所示. 下面对图 2 中的每步流程进行说明 ...

  9. MyBatis缓存通俗易懂

    1.1     mybatis缓存介绍 如下图,是mybatis一级缓存和二级缓存的区别图解: Mybatis一级缓存的作用域是同一个SqlSession,在同一个sqlSession中两次执行相同的 ...

  10. 缓存在哪里_什么是MyBatis缓存技术

    MyBatis缓存 引言 在一个Web项目中,查询数据库中的操作算是一个非常常用的操作,但是有些数据会被经常性的查询,而每一次都去数据库中查询这些重复的数据,会很消耗数据库的资源,同时使得查询效率也很 ...

最新文章

  1. 文件时间信息在测试中的应用
  2. Java语言中的生僻知识
  3. c++美发店管理系统设计_美发店如何打造会员管理系统?掌柜智囊—收银机必不可少...
  4. 最简单的基于FFmpeg的移动端例子:IOS 推流器
  5. CodeForces - 1457E New Game Plus!(贪心)
  6. pyspider 安装 和 快速开始
  7. excel表格不够怎么添加_Excel表格水印,你以前好象添加错了!
  8. php李捷,【问题解答】蝶泳手外划的作用
  9. 有向图的传递闭包实现三种实现(Warshall+DFS+BFS)
  10. js排序算法详解-基数排序
  11. 2022 chrome离线下载包
  12. windows操作系统下新建txt文件快捷键
  13. [扩欧]JZOJ 5855 吃蛋糕
  14. 小项目一:使用fping统计网络中主机的网络连通情况
  15. Unity 制作萌系live2d桌宠:屏幕自适应+交互
  16. 蓝牙耳机哪个品牌比较好?盘点四款好用的蓝牙耳机
  17. sql loader导出数据和导入数据(sqlldr)
  18. Python基础——魔法方法(一)
  19. ERROR: Failed building wheel for pillow and ERROR: running bdist_wheel问题解决
  20. 白话空间统计之:空间异质性

热门文章

  1. 掘金15W沸点简单分析(一)
  2. Chorme 模拟分辨率设置
  3. DTcms-【知识点】-知识点缴获
  4. 《四维全息算法》第六讲--随机、布朗运动、随机游走、混沌、分形混沌与时序拟合分析之间的关系
  5. Linux转发性能评估与优化-转发瓶颈分析与解决方案(补遗)
  6. H264、H265编码概念及I帧P帧B帧
  7. html js post提交表单,JavaScript 实现POST方式提交表单
  8. SEGGER 的硬件异常 分析
  9. 边缘检测——sobel索伯算子 数学原理和应用
  10. 敏捷开发模式几个名词