mybatis的二级缓存使用以及禁用

目录

mybatis 二级缓存配置有两处

全局设置

mapper 设置

测试代码

执行结果

源码执行逻辑

创建 SqlSession

二级缓存配置是否添加

解析 cache 标签

XMLMapperBuilder

MapperBuilderAssistant

CacheBuilder

PerpetualCache

SerializedCache

LoggingCache

将 cache 对象添加到 MappedStatement 对象中

XMLStatementBuilder

MapperBuilderAssistant

查询数据

调用 CachingExecutor 的 query()

调用 TransactionalCacheManager 的 getObject()

调用 SqlSession 的 commit()

调用 CachingExecutor 的 commit()

调用 TransactionalCacheManager 的 commit()

调用 TransactionalCache 的 commit()

缓存失效

执行非 select 操作

XMLStatementBuilder

在 mapper 的 select 标签中设置 flushCache 为 true

CachingExecutor

缓存禁用

xml 中去掉 cache 标签

全局配置

总结


在之前写的 mybatis 文章基础上

mybatis的生命周期-CSDN博客

mybatis的一级缓存使用以及禁用-CSDN博客

mybatis 二级缓存配置有两处

两个一起设置才能生效

全局设置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!-- 配置文件上下文使用的属性值引用外部文件 --><properties resource="jdbc.properties"></properties><settings><setting name="mapUnderscoreToCamelCase" value="true"/><!-- 默认启用二级缓存 --><setting name="cacheEnabled" value="true"/></settings><!-- 定义别名,在 mapper 的返回类型中使用 --><typeAliases><typeAlias type="cn.hahaou.mybatis.cache.leveltwo.entity.Role" alias="role"/></typeAliases><!-- 定义数据库信息,默认使用 development 数据库构建环境 --><environments default="test"><environment id="test"><!-- 采用 jdbc 事务管理 --><transactionManager type="JDBC"/><!-- 配置数据库连接信息 --><dataSource type="POOLED"><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource></environment></environments><!-- 定义映射器 --><mappers><mapper class="cn.hahaou.mybatis.cache.leveltwo.mapper.LevelTwoRoleMapper"/></mappers>
</configuration>

mapper 设置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.hahaou.mybatis.cache.leveltwo.mapper.LevelTwoRoleMapper"><!-- 启用二级缓存标签 --><cache /><resultMap id="roleMap" type="role"><id column="id" property="id" javaType="long" jdbcType="BIGINT"></id><result column="role_name" property="roleName" javaType="string" jdbcType="VARCHAR"></result><result column="note" property="note"></result></resultMap><select id="getRole" parameterType="long" resultType="role">select * from t_role t where t.id = #{id}</select>
</mapper>

测试代码

package cn.hahaou.mybatis.cache.leveltwo;import cn.hahaou.mybatis.cache.leveltwo.mapper.LevelTwoRoleMapper;
import cn.hahaou.util.MybatisUtils;
import org.apache.ibatis.session.SqlSession;/*** 二级缓存测试*/
public class LevelTwoCacheTest {public static void main(String[] args) {{try (SqlSession sqlSession = MybatisUtils.openSession()){LevelTwoRoleMapper roleMapper = sqlSession.getMapper(LevelTwoRoleMapper.class);roleMapper.getRole(1L);sqlSession.commit();}}System.out.println("开启新session查询");{try (SqlSession sqlSession = MybatisUtils.openSession()){LevelTwoRoleMapper roleMapper = sqlSession.getMapper(LevelTwoRoleMapper.class);roleMapper.getRole(1L);sqlSession.commit();}}}
}

执行结果

2023-12-24 16:32:10,019 [main] DEBUG org.apache.ibatis.logging.LogFactory: Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
2023-12-24 16:32:10,100 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.
2023-12-24 16:32:10,101 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.
2023-12-24 16:32:10,101 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.
2023-12-24 16:32:10,101 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.
2023-12-24 16:32:10,148 [main] DEBUG org.apache.ibatis.cache.decorators.LoggingCache: Cache Hit Ratio [cn.hahaou.mybatis.cache.leveltwo.mapper.LevelTwoRoleMapper]: 0.0
2023-12-24 16:32:10,150 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction: Opening JDBC Connection
2023-12-24 16:32:10,347 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource: Created connection 510109769.
2023-12-24 16:32:10,348 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction: Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1e67a849]
2023-12-24 16:32:10,355 [main] DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: select * from t_role t where t.id = ? 
2023-12-24 16:32:10,374 [main] DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Long)
2023-12-24 16:32:10,395 [main] DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==      Total: 1
2023-12-24 16:32:10,401 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction: Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1e67a849]
2023-12-24 16:32:10,407 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction: Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1e67a849]
2023-12-24 16:32:10,407 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource: Returned connection 510109769 to pool.
开启新session查询
2023-12-24 16:32:10,409 [main] DEBUG org.apache.ibatis.cache.decorators.LoggingCache: Cache Hit Ratio [cn.hahaou.mybatis.cache.leveltwo.mapper.LevelTwoRoleMapper]: 0.5

从日志可以得知

第一个 session 查询缓存命中比率为 0,执行 jdbc 查询。

第一个 session 查询缓存命中比率为 0.5,不执行 jdbc 查询。

源码执行逻辑

创建 SqlSession

先通过 Configuration 创建 Executor

Configuration 中的变量 cacheEnabled 对应的值是全局配置的 cacheEnabled 的值,如果未指定,默认值为 true。最终结果返回了一个 CachingExecutor,通过装饰器模式封装了一个 SimpleExecutor。

二级缓存配置是否添加

其中,参数 MappedStatement 对应的是每个 mapper 中定义的用于执行 sql 操作的方法。获取其中的 cache 对象判断是否为空,不为空执行二级缓存逻辑。

解析 cache 标签

XMLMapperBuilder

在 XMLMapperBuilder 中解析 mapper 中定义的 cache 标签。

通过代码得知如下

type 未指定,默认值为 PERPETUAL,对应的是 PerpetualCache,与一级缓存一致。

eviction 未指定,默认值为 LRU,对应的是 LruCache,即缓存淘汰策略使用了 lru 算法。

readOnly 未指定,默认值为 false,但是又对结果进行了取反,所以结果是 true。对用后面的 SerializedCache。

MapperBuilderAssistant

调用 useNewCache() 通过 CacheBuilder 链式编程创建 Cache 对象。

设置 Configuration 的缓存对象为链式创建的。

CacheBuilder

通过 setDefaultImplementations() 得知,如果在调用 useNewCache() 创建 Cache 对象时变量typeClass 和 evictionClass 未指定,分别指定 PerpetualCache 和 LruCache。

在 build() 中循环当前类的 decorators 对象,对 PerpetualCache 使用装饰器模式包装。第一层为 LruCache。

在 setStandardDecorators() 对传入的 Cache 对象(实际为 PerpetualCache)进行装饰器模式包装处理。

鉴于是默认处理,所有最终的 cache 对象如下,中间通过内部变量 delegate 来进行引用。

SynchronizedCache
↓
LoggingCache 计算命中率
↓
SerializedCache 需要缓存的数据需要序列化
↓
LruCache 缓存淘汰策略
↓
PerpetualCache 最终保存缓存的对象

PerpetualCache

最终存储的数据如下

id 为 mapper 全路径。一级缓存是常量字符串。

map 变量 cache 中,key 对应的是 CacheKey,value 对应的是返回的查询结果序列化后的字节数组。一级缓存是返回结果没做任何处理。

 鉴于最终存储的结果是序列化后的字节数组,所以返回的对象需要实现序列化接口 Serializable。

SerializedCache

LoggingCache

针对每次查询请求对变量值进行计数累加,如果查询的数据在缓存中存在,命中数进行累加。

 

命中率计算=命中数/请求总数。

将 cache 对象添加到 MappedStatement 对象中

在 XMLMapperBuilder 中间接调用 XMLStatementBuilder 进行 crud sql 解析处理

XMLStatementBuilder

根据当前查询类型为 select,默认启用缓存。

看到这里感觉很熟悉,因为上面的 flushCache 是一级缓存的标识。

MapperBuilderAssistant

调用 addMappedStatement() 添加到 Configuration  中。

设置 MappedStatement 中二级缓存相关相关的变量

useCache 表示启用二级缓存
cache 表示缓存对象

通过链式编程方式赋值最终构建 MappedStatement 对象。

查询数据

通过 TransactionalCacheManager 这个中间对象来完成。

调用 CachingExecutor 的 query()

在上图中,从 MappedStatement 中获取 cache 对象和 useCache 的值来判断是否启用二级缓存,从上面的分析可以得出,这里 useCache 的判断用于判断当前 statement 的 SqlCommandType 的值,如果为 SELECT 就启用,否则不启用。

调用 TransactionalCacheManager 的 getObject()

通过 getObject() 传入 cache 对象判断对应的 TransactionalCache 在  TransactionalCacheManager 中是否存在

通过 cache 对象判断在 map 对象 transactionalCaches 中是否存在,不存在使用 TransactionalCache 包装添加到 transactionalCaches 中。

因为使用的装饰器模式,最终调用的是 PerpetualCache 中的 cache 变量。

通过 putObject() 传入 cache 对象判断对应的 TransactionalCache 在  TransactionalCacheManager 中是否存在,存在添加到 TransactionalCache 的 entriesToAddOnCommit 变量中。

调用 SqlSession 的 commit()

间接调用 CachingExecutor 的 commit()。

调用 CachingExecutor 的 commit()

调用 TransactionalCacheManager 的 commit()

对于  transactionalCaches 中的 value 值调用对应的 commit() 方法。

调用 TransactionalCache 的 commit()

间接调用 flushPendingEntries()

对应上面调用 putObject() 时向 entriesToAddOnCommit 中添加,因为使用的装饰器模式,最终添加到 PerpetualCache 中的 cache 变量。

其中,对于二级缓存调用 SqlSession 的 close() 也可以做到,对于忘记提交的情况,这里体现了补救措施。

 

上面的测试代码使用了 java 7 中带的 try-with-resources 功能,括号中的变量只能是 Closeable 或者 AutoCloseable 的实现类,在编译器编译时自动添加 close() 防止流关闭的情况。

java中的Closeable与AutoCloseable-CSDN博客

缓存失效

有两种方式

执行非 select 操作

即 insert、delete、update。

XMLStatementBuilder

在执行非查询操作时,useCache 的值为 false,由于该值最终在 MappedStatement 的 useCache 中进行赋值,最终在 CachingExecutor 中会对该值进行判断,如果为 false,不会走缓存的逻辑,会导致缓存失效。

在 mapper 的 select 标签中设置 flushCache 为 true

CachingExecutor

通过上面的分析得知,二级缓存添加是通过 TransactionalCacheManager 的 commit() 来完成的,所以将 flushCache 设置为 false 后,删除 TransactionalCacheManager 中 transactionalCaches 的变量值,导致添加的 TransactionalCache 被清空,所以需要再次查询数据。

缓存禁用

有两种方式

xml 中去掉 cache 标签

作用是 mapper 层级

全局配置

<setting name="cacheEnabled" value="false"/>

默认值为 true,如果设置为 false,mapper 设置后将不起作用。

mybatis 中将二级缓存设置了一半(Configuration 中 cacheEnabled 值为 true),另外一半需要使用者自己处理(mapper 中需要添加 <cache /> 标签进行自定义参数处理,如果不指定参数有默认参数)。

其实二级缓存最终通过 CachingExecutor 来实现,如下图,全局配置在这里进行逻辑处理,如果没配置相关的,则在创建 SqlSession 时最终返回的是 SimpleExecutor。

总结

一级缓存针对的是 SqlSession 层次,二级缓存针对的是 mapper 层次。

最终的缓存类都是 PerpetualCache,只是二级缓存通过装饰器模式串联了多个 cache 实现,可以针对不同的功能串联不同的 cache 实现。

一级缓存和二级缓存都有一个缺点,无法解决缓存共用的问题。所以,针对集群项目不建议使用一级缓存和二级缓存,最好禁用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/226774.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

1.SQL - 概述

1. SQL语句分类 • 数据定义语言&#xff1a;简称DDL(Data Definition Language)&#xff0c;用来定义数据库对象&#xff1a;数据库&#xff0c;表&#xff0c;列等。关键字&#xff1a;create&#xff0c;alter&#xff0c;drop等 • 数据操作语言&#xff1a;简称DML(Data …

2023的AI工具集合,google和claude被禁用解决和edge的copilot

一、前言 AI工具集合 首先&#xff0c;OpenAI的ChatGPT以其深度学习模型和强大的语言处理能力引领了AI聊天机器人的潮流。自2022年11月30日上线以来&#xff0c;它创下了100万用户的注册记录&#xff0c;并被广泛应用于全球财富500强公司。为了实现盈利&#xff0c;OpenAI发布…

【OpenAI Q* 超越人类的自主系统】DQN :Q-Learning + 深度神经网络

深度 Q 网络&#xff1a;用深度神经网络&#xff0c;来近似Q函数 DQN&#xff08;深度 Q 网络&#xff09; 深度神经网络 Q-LearningQ-Learning模型结构损失函数经验回放探索策略流程关联 DQN 优化DDQN&#xff1a;双 DQN&#xff0c;实现无偏估计Dueling DQN&#xff1a;提高…

探索微软Edge:使用方法和心得分享

学习目标&#xff1a; 了解微软Edge的基本功能和使用方法。掌握在微软Edge上进行浏览、搜索和书签管理的技巧。学习如何使用微软Edge进行隐私和安全管理。探索微软Edge的扩展和其他高级功能。 学习内容&#xff1a; 微软Edge的简介&#xff1a;了解微软Edge的起源、特点和与其…

【halcon深度学习】dev_display_dl_data 移植到C# 上篇

效果展示 前言 在研究halcon深度学习的时候,会发现halcon的例程里面用到了大量的二次封装库函数。这些库函数内部也是由基础的算子组成。我们在halcon的开发环境里面用的很爽,但是一旦要在C#中使用,就会报错。 一开始,我想避开这个移植过程,直接使用halcon引擎(HDevEngi…

运筹视角下,体系化学习机器学习算法原理的实践和总结

文章目录 引言目标设计目标实践文章汇总经验总结一则预告 引言 上两周总结了我在体系化学习运筹学基础知识方面的个人经验&#xff0c;看过那篇文章的人可能知道&#xff0c;今年我还花了很多时间学习机器学习中各种模型的算法原理。 在工业应用中&#xff0c;机器学习和运筹…

Spring基础IoC(控制反转)与DI(依赖注入)

1. Spring 基础 1.1 什么是Spring框架&#xff1f;它能带来那些好处&#xff1f; Spring 是一个开源的轻量级的 Java 开发框架&#xff0c;可以帮助开发人员更高效的进行开发&#xff0c;主要优势在于简化开发和框架整合。 Spring框架整合了很多模块&#xff0c;这些模块可以…

智能优化算法应用:基于厨师算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于厨师算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于厨师算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.厨师算法4.实验参数设定5.算法结果6.参考文献7.MA…

2023/12/21作业

思维导图 代码 .text .global _start _start: 灯1 gpio时钟使能 [4]->1 0x5000A28 LDR R0,0x50000A28 指定寄存器地址 LDR R1,[R0]将寄存器取出放到R1 ORR R1,R1,#(0x1<<4)将第四位设置为1 STR R1,[R0]读取R0寄存器到R1 PE…

传统项目基于tomcat cookie单体会话升级分布式会话解决方案

传统捞项目基于servlet容器 cookie单体会话改造分布式会话方案 ##引入redis,spring-session依赖 <!--redis依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>&…

OKCC语音机器人的人机耦合来啦

目前市场上语音机器人的外呼形式基本就分为三种&#xff0c;一种纯AI外呼&#xff0c;第二种也是目前主流的AI外呼转人工。那么第三种也可能是未来的一种趋势&#xff0c;人机耦合&#xff0c;或者也叫人机协同。 那么什么是人机耦合呢&#xff1f; 人机耦合是为真人坐席创造相…

Featured Based知识蒸馏及代码(3): Focal and Global Knowledge (FGD)

文章目录 1. 摘要2. Focal and Global 蒸馏的原理2.1 常规的feature based蒸馏算法2.2 Focal Distillation2.3 Global Distillation2.4 total loss3. 实验完整代码论文: htt

逻辑卷学习

磁盘分区的缺点 1.无法扩容 2.必须使用的空间 3.没有备份: 一、逻辑卷的定义 LVM 是 Logical Volume Manager 的简称&#xff0c;译为中文就是逻辑卷管理。它是 Linux 下对硬盘分区的一种管理机制。LVM 适合于管理大存储设备&#xff0c;并允许用户动态调整文件系统的大小…

【电商项目实战】MD5登录加密及JSR303自定义注解

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是Java方文山&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的专栏《电商项目实战》。&#x1f3af;&#x1f3af; &am…

鸿蒙开发之崩溃信息收集FaultLogger

前申&#xff1a;果然系统的API没有让我失望&#xff0c;日志完全看不出来崩溃原因所在 一、使用 logCrash() {FaultLogger.query(FaultLogger.FaultType.JS_CRASH,(err,val) > {if (err) {console.log(fault log get an errJSON.stringify(err))return}let len val.lengt…

【C++】map和set

目录 1. 关联式容器 2. 键值对 3. 树形结构的关联式容器 4.set的介绍 接口count 接口lower_bound和upper_bound insert插入接口 5.map的介绍 接口insert 接口operator[] 6.multiset 7.multimap 8.map和set相关OJ 1. 关联式容器 vector 、 list 、 deque、forward_li…

electron使用electron-builder进行MacOS的 打包、签名、公证、上架、自动更新

一、前言 由于electron在macOS下的坑太多&#xff0c;本文不可能把所有的问题都列出来&#xff0c;也不可能把所有的解决方案贴出来&#xff1b;本文也不太会讲解每一个配置点为什么要这么设置的原因&#xff0c;因为有些点我也说不清&#xff0c;我尽可能会说明的。所以&…

运维实践|MySQL查询时如何正确使用正则表达式

&#x1f4eb; 作者简介&#xff1a;「六月暴雪飞梨花」&#xff0c;专注于研究Java&#xff0c;就职于科技型公司后端工程师 &#x1f3c6; 近期荣誉&#xff1a;华为云云享专家、阿里云专家博主、 &#x1f525; 三连支持&#xff1a;欢迎 ❤️关注、&#x1f44d;点赞、&…

Google Play上架:2023年度总结报告

今天是2023年的最后一个工作日&#xff0c;今天用来总结一下2023年关于谷歌商店上架的相关政策改动和对应的拒审解决方法。 目录 政策更新与改动2023 年 2 月 22 日2023 年 4 月5 日2023 年 7 月 12 日2023 年 10 月 25 日 开发者计划政策拒审邮件内容和解决办法 政策更新与改…

vue项目hdr格式文件放在assets下rgbeloader.load获取不到问题解决

如下图 我再App.vue组件中这样写 艾特符号定位 告诉系统 要src下的assets下的xhdr下的xidis.hdr 但是运行项目 他会告诉你找不到这个资源 我们改一下 我们组件时 App.vue 与assets同在 src目录下 用 ./去找 这样也是找不到的 我们需要将它放在静态资源包public下 public路…