mybatis源码 (四) —— 一级缓存和二级缓存

2024-06-15 21:08

本文主要是介绍mybatis源码 (四) —— 一级缓存和二级缓存,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

MyBatis的缓存分为两种

  1. 一级缓存,一级缓存是SqlSession级别的缓存,对于相同的查询,会从缓存中返回结果而不是查询数据库(也叫本地缓存)默认会启用
  2. 二级缓存,二级缓存是Mapper级别的缓存,定义在Mapper文件的标签中并需要开启此缓存,默认关闭

先看二级缓存:开启
org.apache.ibatis.executor.CachingExecutor#query

  //被ResultLoader.selectList调用@Overridepublic <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)throws SQLException {Cache cache = ms.getCache();//默认情况下是没有开启缓存的(二级缓存).要开启二级缓存,你需要在你的 SQL 映射文件中添加一行: <cache/>//简单的说,就是先查CacheKey,查不到再委托给实际的执行器去查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.putObject(cache, key, list); // issue #578 and #116}return list;}}return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);}
  1. 根据flushCache=true或者flushCache=false判断是否要清理二级缓存
  2. 从tcm中获取查询结果,这个tcm解释一下,
  3. 如果没有从MyBatis二级缓存中拿到数据,那么就会查一次数据库,然后放到MyBatis二级缓存中去

总结:二级缓存是存在MappedStatement 即mapper中


再看一级缓存:
org.apache.ibatis.executor.BaseExecutor#query

  @Overridepublic <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.");}//先清局部缓存,再查询.但仅查询堆栈为0,才清。为了处理递归调用if (queryStack == 0 && ms.isFlushCacheRequired()) {clearLocalCache();}List<E> list;try {//加一,这样递归调用到上面的时候就不会再清局部缓存了queryStack++;//先根据cachekey从localCache去查list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;if (list != null) {//若查到localCache缓存,处理localOutputParameterCachehandleLocallyCachedOutputParameters(ms, key, parameter, boundSql);} else {//从数据库查list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);}
  1. 先根据cachekey从localCache去查
  2. 若查到localCache缓存,处理localOutputParameterCache
  3. 没查到再从数据库查
  //从数据库查private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {List<E> list;//先向缓存中放入占位符???localCache.putObject(key, EXECUTION_PLACEHOLDER);try {list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);} finally {//最后删除占位符localCache.removeObject(key);}//加入缓存localCache.putObject(key, list);//如果是存储过程,OUT参数也加入缓存if (ms.getStatementType() == StatementType.CALLABLE) {localOutputParameterCache.putObject(key, parameter);}return list;}

从数据库查到数据之后保存在一级缓存里面
总结:一级缓存是在BaseExecutor中维护的,也就是说一级缓存对应的SQLSession


而对于org.apache.ibatis.executor.CachingExecutor#update

  @Overridepublic int update(MappedStatement ms, Object parameterObject) throws SQLException {//刷新缓存完再updateflushCacheIfRequired(ms);return delegate.update(ms, parameterObject);}

二级缓存的更新操作,先清除缓存,在更新

org.apache.ibatis.executor.BaseExecutor#update

  @Overridepublic int update(MappedStatement ms, Object parameter) throws SQLException {ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());if (closed) {throw new ExecutorException("Executor was closed.");}//先清局部缓存,再更新,如何更新交由子类,模板方法模式clearLocalCache();return doUpdate(ms, parameter);}

一级缓存的更新操作,先清除缓存,在更新

这篇关于mybatis源码 (四) —— 一级缓存和二级缓存的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1064576

相关文章

MyBatis分页查询实战案例完整流程

《MyBatis分页查询实战案例完整流程》MyBatis是一个强大的Java持久层框架,支持自定义SQL和高级映射,本案例以员工工资信息管理为例,详细讲解如何在IDEA中使用MyBatis结合Page... 目录1. MyBATis框架简介2. 分页查询原理与应用场景2.1 分页查询的基本原理2.1.1 分

MyBatis Plus实现时间字段自动填充的完整方案

《MyBatisPlus实现时间字段自动填充的完整方案》在日常开发中,我们经常需要记录数据的创建时间和更新时间,传统的做法是在每次插入或更新操作时手动设置这些时间字段,这种方式不仅繁琐,还容易遗漏,... 目录前言解决目标技术栈实现步骤1. 实体类注解配置2. 创建元数据处理器3. 服务层代码优化填充机制详

mybatis映射器配置小结

《mybatis映射器配置小结》本文详解MyBatis映射器配置,重点讲解字段映射的三种解决方案(别名、自动驼峰映射、resultMap),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定... 目录select中字段的映射问题使用SQL语句中的别名功能使用mapUnderscoreToCame

mybatis-plus如何根据任意字段saveOrUpdateBatch

《mybatis-plus如何根据任意字段saveOrUpdateBatch》MyBatisPlussaveOrUpdateBatch默认按主键判断操作类型,若需按其他唯一字段(如agentId、pe... 目录使用场景方法源码方法改造首先在service层定义接口service层接口实现总结使用场景my

MyBatis ParameterHandler的具体使用

《MyBatisParameterHandler的具体使用》本文主要介绍了MyBatisParameterHandler的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参... 目录一、概述二、源码1 关键属性2.setParameters3.TypeHandler1.TypeHa

MyBatis-plus处理存储json数据过程

《MyBatis-plus处理存储json数据过程》文章介绍MyBatis-Plus3.4.21处理对象与集合的差异:对象可用内置Handler配合autoResultMap,集合需自定义处理器继承F... 目录1、如果是对象2、如果需要转换的是List集合总结对象和集合分两种情况处理,目前我用的MP的版本

使用Spring Cache本地缓存示例代码

《使用SpringCache本地缓存示例代码》缓存是提高应用程序性能的重要手段,通过将频繁访问的数据存储在内存中,可以减少数据库访问次数,从而加速数据读取,:本文主要介绍使用SpringCac... 目录一、Spring Cache简介核心特点:二、基础配置1. 添加依赖2. 启用缓存3. 缓存配置方案方案

Java实现本地缓存的四种方法实现与对比

《Java实现本地缓存的四种方法实现与对比》本地缓存的优点就是速度非常快,没有网络消耗,本地缓存比如caffine,guavacache这些都是比较常用的,下面我们来看看这四种缓存的具体实现吧... 目录1、HashMap2、Guava Cache3、Caffeine4、Encache本地缓存比如 caff

MyBatis-Plus 与 Spring Boot 集成原理实战示例

《MyBatis-Plus与SpringBoot集成原理实战示例》MyBatis-Plus通过自动配置与核心组件集成SpringBoot实现零配置,提供分页、逻辑删除等插件化功能,增强MyBa... 目录 一、MyBATis-Plus 简介 二、集成方式(Spring Boot)1. 引入依赖 三、核心机制

MyBatis的xml中字符串类型判空与非字符串类型判空处理方式(最新整理)

《MyBatis的xml中字符串类型判空与非字符串类型判空处理方式(最新整理)》本文给大家介绍MyBatis的xml中字符串类型判空与非字符串类型判空处理方式,本文给大家介绍的非常详细,对大家的学习或... 目录完整 Hutool 写法版本对比优化为什么status变成Long?为什么 price 没事?怎