面试官:说一下 MyBatis 的一级缓存和二级缓存 ?
目录
1. MyBatis 的缓存机制
2. 为什么不默认开启 MyBatis 的二级缓存
3. MyBatis 如何开启二级缓存
4. MyBatis 有哪些缓存清除策略
1. MyBatis 的缓存机制
MyBayis 中包含两级缓存:一级缓存和二级缓存
1. 一级缓存是 SqlSession 级别的,是 MyBatis 自带的缓存功能,默认是开启的,并且无法关闭,所以当有两个 SqlSession 执行相同的 SQL 时,就没有用到一级缓存,而是查询了两次数据库。
2. 二级缓存是 Mapper 级别的,只要是同一个 Mapper,无论使用多少个 SqlSession 进行操作,数据都是共享的,所以多个 SqlSession 可以共享二级缓存。但是 MyBatis 的二级缓存默认是关闭的,需要时可以手动开启。此外,二级缓存还可以使用第三方的缓存,例如:Ehcache。
2. 为什么不默认开启 MyBatis 的二级缓存
为什么不默认开启二级缓存呢 ? 缓存不是可以加速程序的查询性能吗 ?
MyBatis 不默认开启二级缓存的原因有以下几点:
1. 缓存粒度过大:因为二级缓存是一个全局缓存,可以缓存多个不同的查询结果集。默认情况下,MyBatis 是不知道哪些查询结果需要缓存,哪些查询结果不需要缓存。当开启二级缓存后,所有的查询结果都尝试使用缓存,这就可能会导致缓存的数据不准确或者不一致性。

例如上图,三次查询操作查询到的结果可能不一致,此时 MyBatis 默认不知道缓存哪个查询结果,这样就存在缓存不准确的风险。
2. 并发性问题:在多线程情况下,开启二级缓存,如果没有及时清空或刷新缓存,就可能会导致缓存和数据库数据不一致性问题。
此处的并发性问题可以类比到 Redis 和 MySQL 数据不一致性问题 :

关于多线程情况下的缓存和数据库不一致性问题以及解决方案,可以看我的这篇博客:https://blog.csdn.net/xaiobit_hl/article/details/132453064
3. 内存占用问题:开启二级缓存之后,缓存的数据需要占用大量的内存空间,如果没有合适的策略来管理缓存,可能就会导致内存占用过多的问题。
4. 复杂性问题:二级缓存的配置需要考虑诸多因素,例如:缓存的刷新以及缓存的清理,这都需要较好的缓存策略来处理,这就加大了开发的复杂性,并且有可能引入新的问题。
基于以上问题,MyBatis 选择默认关闭二级缓存,当开发人员确认某些查询可以受益于缓存时,再手动开启二级缓存来使用即可(把主动权交给了开发人员)。
3. MyBatis 如何开启二级缓存
MyBatis 中开启二级缓存需要两步操作:
- 在 mapper 对应的 xml 中添加 <cache> 标签;
- 在 xml 中给需要缓存的标签设置 useCache="true"。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper"><cache/><select id="getAll" resultType="UserInfo" useCache="true">select count(*) from userinfo;</select>
</mapper>
进行单元测试:
@SpringBootTest
class UserMapperTest {@Resourceprivate UserMapper userMapper;@Testvoid getAll() {int ret1 = userMapper.getAll();System.out.println("查询结果:" + ret1);int ret2 = userMapper.getAll();System.out.println("查询结果:" + ret2);}
}
【说明】
此处在外部方法,调用两次 getAll() 方法,它一定会使用两个 SqlSession,只有在一个 getAll() 方法里面执行两条相同的 SQL 时,才会使用同一个 SqlSession。
如何判断是否走缓存?(properties 文件中配置执行打印 SQL)
- 如果两次查询都打印了 SQL 语句,说明没有走缓存,
- 如果第一次查询打印了 SQL 语句,第二次没有打印,说明第二次查询走的是缓存。
【执行结果】

【结果分析】
执行结果很显然,第二次查询走了缓存。虽然调用了两次 getAll() 方法,使用了两个 SqlSession,但是因为我前面开启了二级缓存,二级缓存的作用域是整个 mapper,所以不管是用了几个 SqlSession,第二次查询肯定会走缓存。
如果关闭二级缓存,那么两次查询都会查询数据库(创建了两个 SqlSession,都打印了 SQL),执行结果如下:

【一级缓存示例】
在关闭二级缓存的情况下,还想使得第二次查询走缓存,可以通过在方法上加一个 @Transactional 注解就可以做到。
当我们在方法上加上 @Transactional 注解的时候,事物里面的所有方法就会使用一个 SqlSession 来进行操作,那么第二次查询也就自然而然会走缓存了。

但是这种做法是不推荐的,使用 @Transactional 注解相当于用了新方法解决旧问题,然后又引入了新的问题。@Transactional 底层是基于动态代理来实现的,操作代理对象肯定不如操作原对象的性能好,所以又引入了性能问题。
4. MyBatis 有哪些缓存清除策略
关于 MyBatis 二级缓存的一个补充:
- 使用二级缓存时,所有的 select 语句的结果将会被缓存;
- 所有的 update,insert,delete 语句将会刷新缓存;
- 缓存默认使用 LRU 最近最少使用算法来清除不需要的缓存; -- eviction
- 缓存不会定时刷新,没有刷新间隔; -- flushInterval
- 缓存默认最多保存 1024 个引用; -- size
- 缓存默认被视为读写缓存(prototype),对象不共享,更安全。 -- readOnly
上述这些特性都可以在 <cache/> 标签里进行设置:
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
这行设置的意思是缓存使用 FIFO 的清除策略,刷新间隔为 60s,缓存能保存的最大引用数为 512,并且设置只读缓存(单例)。
MyBatis 缓存的清除策略有 4 种可以设置:
- LRU:最近最少使用;
- FIFO:先进先出,按照对象的缓存顺序来清除缓存;
- SOFT:软引用,普通 GC 不回收,触发 Full GC 才回收。
- WEAK:弱引用,触发任何 GC 都会回收,例如:Young GC,Full GC。
对于 LRU 不太理解的,可以看我的这篇博客:https://blog.csdn.net/xaiobit_hl/article/details/132418631
虽然 MyBatis 的缓存看起来非常牛皮,但是它只能在单机架构中花拳绣腿,分布式架构还得看 Redis。
相关文章:
面试官:说一下 MyBatis 的一级缓存和二级缓存 ?
目录 1. MyBatis 的缓存机制 2. 为什么不默认开启 MyBatis 的二级缓存 3. MyBatis 如何开启二级缓存 4. MyBatis 有哪些缓存清除策略 1. MyBatis 的缓存机制 MyBayis 中包含两级缓存:一级缓存和二级缓存 1. 一级缓存是 SqlSession 级别的,是 MyBati…...
Ajax与jQuery
目录 Ajax是一种异步无刷新的技术 Ajax的优点: 可以无需刷新页面与服务器端进行通信允许根据用户事件来更新部分页面内容 Ajax的缺点: 没有浏览历史,不能回退存在跨域问题(同源)SEO(搜索引擎优化&#x…...
色温曲线坐标轴的选取:G/R、G/B还是R/G、B/G ?
海思色温曲线坐标 Mstar色温曲线坐标 高通色温曲线坐标 联咏色温曲线坐标 查看各家白平衡调试界面,比如海思、Mstart、高通等调试资料,白平衡模块都是以R/G B/G作为坐标系的两个坐标轴,也有方案是以G/R G/B作为坐标系的两个坐标轴。 以G/R G…...
maven部署
一、下载Maven 地址:Maven – Download Apache Maven 二、解压缩,设置环境变量 tar -xvf apache-maven-3.8.8-bin.tar.gz export MAVEN_HOME/opt/apache-maven-3.8.8 export PATH$MAVEN_HOME/bin:$PATH echo $MAVEN_HOME echo $PATH mvn -v...
docker进阶作业
一、使用mysql:5.6和 owncloud 镜像,构建一个个人网盘。 安装Docker:确保已在CentOS 7.5上安装了Docker。 拉取MySQL 5.6镜像:使用以下命令从Docker Hub上拉取MySQL 5.6镜像。 docker pull mysql:5.6 运行MySQL容器:使用以下命令…...
HTML+JavaScript+CSS DIY 分隔条splitter
一、需求分析 现在电脑的屏幕越来越大,为了利用好宽屏,我们在设计系统UI时喜欢在左侧放个菜单或选项面板,在右边显示与菜单或选项对应的内容,两者之间用分隔条splitter来间隔,并可以通过拖动分隔条splitter来动态调研…...
Oracle-day5:新增、复制建表、表结构、表数据、删除
目录 一、insert新增数据 二、复制建表 三、表结构修改 四、查看表结构、表数据处理 五、修改表数据 六、删除语句 八、练习题 一、insert新增数据 /* ---------- 一、DML 数据操作语言-------- -- 1、增加数据 insert 语法:insert into 表名 (列1,列2,…...
Scratch 画画的技巧
前言 美术是一种艺术,且不局限于纸张,就像电脑绘图也属于美术。我至今已有三年多的画龄,经验丰富,尤其擅长在scratch造型编辑器上画矢量图。今天给大家分享一些实用的技巧。 1.讲解 用橡皮工具给一个圆擦出“橡皮洞” 橡皮工具&a…...
国际版阿里云/腾讯云:阿里弹性云手机正式公测
阿里弹性云手机正式公测 什么是“云手机”?与我们传统的手机有何区别?它又有什么用处呢?当你接触到云手机概念的时候,是不是也会有这一连串的疑问。本文将为你揭开云手机的奥秘面纱。 2021年12月1日,阿里弹性云手机正…...
服务器数据恢复- RAID5出现故障后恢复数据和操作系统的案例
服务器数据恢复环境: 某品牌服务器中有4块SAS硬盘组建了一组RAID5阵列,另外1块磁盘作为热备盘使用。上层操作系统为redhat linux,部署了一个数据库是oracle的OA。 服务器故障&初检: RAID5中一块磁盘离线后热备盘未自动激活re…...
Vue3实现可视化拖拽标签小程序
介绍 实现功能:可视化标签拖拽,双击标签可修改标签内容 HTML结构 <div class"box" v-move><div class"header">标签1</div><div dblclick"startEditing" v-if"!isEditing">{{content…...
SSM 前端使用AJAX方式,fromdata文件格式上传二进制流文件
今天在上课的时候,遇到了一个比较坑的问题,有个学生拿来了她的代码,让我给她看看为什么传值传不过来。 首先,前端是这样的: function upload(){var formData new FormData();formData.append(images, $(#previewImg)…...
LeetCode-455-分发饼干-贪心算法
题目描述: 假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。 对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 jÿ…...
新版 Next.js 从入门到入土
本教程用的Next.js 是 13 版本 Next.js 简介 完善的React项目,搭建轻松自带数据同步,解决服务端渲染最大难点丰富的插件灵活配置 创建第一个项目 手动创建 初始化 npm init安装所需要的依赖包 npm install --save react react-don next增加快捷命…...
OpenCV(十):图像缩放、翻转、拼接的介绍与使用
目录 (1)图像缩放:resize() (2)图像翻转: flip() (3)图像拼接:hconcat() 和vconcat() (1)图像缩放:resize() 使用 cv2.resize() 函…...
C++ 学习之 构造函数 和 析构函数
前言 总的来说,构造函数负责对象的初始化,而析构函数负责对象的清理和资源释放。它们是C面向对象编程中非常重要的概念,用于管理对象的生命周期,确保对象在创建和销毁时都能够正确地进行初始化和清理。 正文 看代码 class perso…...
加快 MySQL 数据迁移
目录 一、先导 1. 自建目标实例 2. 配置目标主从 二、源导出 1. 生成查询用户权限的SQL语句 2. 生成权限的SQL语句 3. 生成创建非主键索引的SQL语句 4. 导出源库结构 5. 导出源库数据 三、目标导入 1. 目标实例设置 2. 创建用户与权限 3. 处理结构导出文件 4. 导…...
CANalyzer panel
(1205条消息) CAPL 脚本中对信号,系统变量,环境变量的 事件响应_capl programs脚本怎么写信号运算_蚂蚁小兵的博客-CSDN博客 注意环境变量是在工程关联的dbc中创建的;而系统变量是在CANoe工程工具栏的”Environment”下的”System Variables”…...
延迟队列的理解与使用
目录 一、场景引入 二、延迟队列的三种场景 1、死信队列TTL对队列进行延迟 2、创建通用延时消息死信队列 对消息延迟 3、使用rabbitmq的延时队列插件 x-delayed-message使用 父pom文件 pom文件 配置文件 config 生产者 消费者 结果 一、场景引入 我们知道可以通过TT…...
jQuery成功之路——jQuery的DOM操作简单易懂
jQuery的DOM操作 1.jQuery操作内容 jQuery操作内容 1. text() 获取或修改文本内容 类似于 dom.innerText 2. html() 获取或修改html内容 类似 dom.innerHTML 注意: 1. text() 是获取设置所有 2. html() 是获取第一个,设置所有 <!DOCTYPE html> <html lang"zh…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...
10-Oracle 23 ai Vector Search 概述和参数
一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI,使用客户端或是内部自己搭建集成大模型的终端,加速与大型语言模型(LLM)的结合,同时使用检索增强生成(Retrieval Augmented Generation &#…...
BLEU评分:机器翻译质量评估的黄金标准
BLEU评分:机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域,衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标,自2002年由IBM的Kishore Papineni等人提出以来,…...
深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏
一、引言 在深度学习中,我们训练出的神经网络往往非常庞大(比如像 ResNet、YOLOv8、Vision Transformer),虽然精度很高,但“太重”了,运行起来很慢,占用内存大,不适合部署到手机、摄…...
