面试官:说一下 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…...
基于QR分解与肘部法则的稀疏传感器优化布置方法
1. 项目概述:从海量数据到“聪明”的传感器网络在流体动力学、航空航天、环境监测乃至结构健康诊断等众多工程与科学领域,我们常常面临一个共同的困境:我们渴望获得物理场(如速度、压力、温度)在空间和时间上的完整、高…...
Unity ECS帧同步实战:确定性模拟与Job化网络Tick
1. 这不是“又一个Unity网络教程”,而是帧同步在ECS架构下的真实落地切口很多人一看到“Unity多人对战”就下意识点开,结果发现是PhotonMonoBehaviour的旧路子:对象池、RPC调用、状态同步、插值补偿……代码越写越厚,逻辑越埋越深…...
【应用实战】基于Dify与多Agent的凭证与档案管理
一、智能文档处理:基于Dify与多Agent的凭证与档案管理革新 在金融行业,文档处理贯穿业务始终。传统的纯人工方式不仅耗时费力,而且极易出错。智能文档处理(Intelligent Document Processing, IDP)融合了OCR、自然语言处…...
【光学】偏振光线追迹Matlab仿真
✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、程序设计科研仿真。🍎完整代码获取 定制创新 论文复现点击:Matlab科研工作室👇 关注我领取海量matlab电子书和数学建模资料 dz…...
在线语音工具大比拼:顶伯胜在哪?
🎯 在线语音工具大比拼:顶伯、剪映、配音阁、讯飞,微软 TTS 版胜在哪?在内容创作日益多元的今天,语音合成工具已成为视频博主、教育从业者、有声书制作者不可或缺的伙伴。市面常见的选项包括剪映内置配音、配音阁、讯飞…...
Windows右键菜单终极清理指南:用ContextMenuManager告别杂乱,重获高效桌面
Windows右键菜单终极清理指南:用ContextMenuManager告别杂乱,重获高效桌面 【免费下载链接】ContextMenuManager 🖱️ 纯粹的Windows右键菜单管理程序 项目地址: https://gitcode.com/gh_mirrors/co/ContextMenuManager 还在为Windows…...
从账单明细看 Taotoken 按 Token 计费如何实现成本精细化
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 从账单明细看 Taotoken 按 Token 计费如何实现成本精细化 1. 引言:从模糊估量到精确计量 在接入和使用大模型 API 时&…...
基于Java的外卖点餐配送系统_43lq510m
目录 同行可拿货,招校园代理 ,本人源头供货商项目概述技术栈核心功能模块项目亮点部署方式学习价值 项目技术支持获取博主联系方式 源码获取详细视频演示 :同行可合作点击我获取源码->获取博主联系方式->进我个人主页--> 同行可拿货,招校园代理 ,本人源头供…...
AI Agent游戏测试革命:自动生成10万+边界用例,覆盖率提升3.2倍——附可运行Python测试Agent源码
更多请点击: https://intelliparadigm.com 第一章:AI Agent游戏行业应用全景图 AI Agent 正在重塑游戏开发、运营与玩家体验的全生命周期。从智能NPC的行为建模,到自动化测试与关卡生成,再到实时个性化内容推荐与反作弊决策&…...
XZ63C,18V输入,CMOS输出电压检测芯片
产品概述这系列芯片是使用 CMOS 技术开发的高精度、低功耗、小封装电压检测芯片。检测电压在小温度漂移的情况下保持极高的精度。输出配置是 CMOS 输出。产品特点● 封装:SOT23-3,TO92● 输出配置:CMOS● 工作电压:1.5V-18V …...
