当前位置: 首页 > article >正文

MyBatis 延迟加载与缓存

一、延迟加载策略:按需加载,优化性能

1. 延迟加载 vs 立即加载:核心区别

  • 立即加载:主查询(如查询用户)执行时,主动关联加载关联数据(如用户的所有账号)。
    • 场景:多对一查询(如账号关联用户),需立即获取关联数据。
  • 延迟加载:主查询执行时暂不加载关联数据,仅当程序访问关联数据时,再触发子查询。
    • 场景:一对多查询(如用户关联多个账号),减少初始查询压力。

举个小例子: 

场景:查询用户信息时不立即加载其订单,仅在需要查看订单时再触发查询。
示例:电商用户详情页先展示用户姓名、地址,点击 “查看订单” 按钮时,才加载该用户的订单列表。 

 2. 多对一延迟加载实现(Account → User)

步骤解析:

1、定义关联查询:主查询仅查账号表,关联用户信息通过子查询延迟加载。

<!-- 主查询:仅查账号 -->
<select id="findAll" resultMap="accountMap">SELECT * FROM account
</select><!-- 子查询:通过用户ID查用户信息 -->
<select id="findById" parameterType="int" resultType="User">SELECT * FROM user WHERE id = #{id}
</select>

2、配置延迟加载:通过 association 标签指定子查询路径和参数。

<resultMap type="Account" id="accountMap"><association property="user"          <!-- Account类中的User属性 -->javaType="User"          <!-- 关联对象类型 -->select="findById"        <!-- 子查询方法名 -->column="uid"             <!-- 主查询结果中用于关联的列(账号表的uid) -->/>
</resultMap>

3、全局开启延迟加载:在 SqlMapConfig.xml 中配置。

<settings><setting name="lazyLoadingEnabled" value="true"/>   <!-- 开启延迟加载 --><setting name="aggressiveLazyLoading" value="false"/> <!-- 关闭积极加载(默认会加载所有关联数据) -->
</settings>

 测试验证:

@Test
public void testLazyLoading() {List<Account> accounts = accountMapper.findAll();for (Account account : accounts) {System.out.println("账号金额:" + account.getMoney()); // 主查询执行时仅输出金额System.out.println("用户名称:" + account.getUser().getUsername()); // 首次访问user时触发子查询}
}

 3. 一对多延迟加载实现(User → Accounts)

 核心配置:

<!-- 主查询:仅查用户表 -->
<select id="findAll" resultMap="userMap">SELECT * FROM user
</select><resultMap type="User" id="userMap"><collection property="accounts"       <!-- User类中的账号列表属性 -->ofType="Account"          <!-- 集合元素类型 -->select="com.qcbyjy.mapper.AccountMapper.findByUid" <!-- 子查询:通过用户ID查账号 -->column="id"                <!-- 主查询结果中的用户ID -->/>
</resultMap><!-- 子查询:根据用户ID查账号 -->
<select id="findByUid" parameterType="int" resultType="Account">SELECT * FROM account WHERE uid = #{uid}
</select>
关键区别:
  • 多对一用 association(单个对象),一对多用 collection(集合)。
  • 子查询参数通过 column 传递主查询结果中的字段(如用户表的 id)。

 二、MyBatis 缓存机制:减少数据库访问

 1. 缓存的核心价值

  • 定义:将频繁查询的数据临时存储在内存中,避免重复访问数据库,提升查询速度。
  • 适用场景:读多写少、数据更新不频繁的数据(如字典表、配置信息)。

 2. 一级缓存:SqlSession 级别的缓存

(1)本质与作用

  • 作用域:基于 SqlSession 对象,同一 SqlSession 内的相同查询会直接从缓存获取结果。
  • 实现原理SqlSession 内部维护一个 HashMap,键为查询的唯一标识(SQL + 参数),值为查询结果对象。

 (2)验证一级缓存

@Test
public void testFirstLevelCache() {// 同一 SqlSession 内的两次相同查询User user1 = userMapper.findById(1);User user2 = userMapper.findById(1); // 直接从缓存获取,不执行 SQLSystem.out.println(user1 == user2); // 输出 true(对象引用相同)
}
(3)缓存失效场景
  • SqlSession 关闭或提交(commit)。
  • 执行 update/insert/delete 操作(会清空缓存)。
  • 手动调用 session.clearCache() 清空缓存。

 3. 二级缓存:SqlSessionFactory 级别的缓存

(1)核心概念

  • 作用域:基于 SqlSessionFactory,跨 SqlSession 共享缓存(如多个 SqlSession 执行相同查询)。
  • 实现条件
    1. 实体类需实现 Serializable 接口(支持序列化存储)。
    2. 在 SqlMapConfig.xml 中开启二级缓存(默认已开启)。
    3. 在 Mapper 中配置 <cache/> 标签。

 (2)配置步骤

1、 实体类实现序列化

public class User implements Serializable {// 省略属性和方法
}

2、Mapper 中启用缓存

<mapper namespace="com.qcbyjy.mapper.UserMapper"><cache/> <!-- 启用二级缓存 --><select id="findById" resultType="User" useCache="true">SELECT * FROM user WHERE id = #{id}</select>
</mapper>

3、配置缓存策略(可选)

<cache eviction="LRU"       <!-- 缓存淘汰策略:LRU(最近最少使用) -->flushInterval="60000" <!-- 自动刷新间隔(毫秒) -->size="512"           <!-- 最大缓存对象数 -->readOnly="true"      <!-- 是否只读:true(共享对象)/ false(复制对象) -->
/>

(3)缓存优先级与刷新

  • 优先级:二级缓存 > 一级缓存 > 数据库查询。
  • 刷新机制:执行 update/insert/delete 时,会清空对应 Mapper 的二级缓存。

 (4)测试验证

@Test
public void testSecondLevelCache() {try (SqlSession session1 = factory.openSession()) {UserMapper mapper1 = session1.getMapper(UserMapper.class);User user1 = mapper1.findById(1); // 首次查询,命中数据库}try (SqlSession session2 = factory.openSession()) {UserMapper mapper2 = session2.getMapper(UserMapper.class);User user2 = mapper2.findById(1); // 第二次查询,命中二级缓存,不执行 SQL}
}

 三、总结:性能优化核心要点

技术核心作用关键配置
延迟加载减少初始查询数据量,提升响应速度lazyLoadingEnabledassociation/collection 的 select 属性
一级缓存减少同一会话内的重复查询自动生效,无需额外配置(注意 SqlSession 生命周期)
二级缓存跨会话共享缓存,减少数据库压力实体类序列化、<cache/> 标签、缓存策略配置

合理运用延迟加载和缓存,能显著提升 MyBatis 应用的性能,但需根据业务场景灵活选择,避免过度使用导致数据不一致或内存溢出。

相关文章:

MyBatis 延迟加载与缓存

一、延迟加载策略&#xff1a;按需加载&#xff0c;优化性能 1. 延迟加载 vs 立即加载&#xff1a;核心区别 立即加载&#xff1a;主查询&#xff08;如查询用户&#xff09;执行时&#xff0c;主动关联加载关联数据&#xff08;如用户的所有账号&#xff09;。 场景&#xf…...

C++函数三剑客:缺省参数·函数重载·引用的高效编程指南

前引&#xff1a;在C编程中&#xff0c;缺省参数、函数重载、引用是提升代码简洁性、复用性和效率的三大核心机制。它们既能减少冗杂的代码&#xff0c;又能增强接口设计的灵活性。本文将通过清晰的理论解析与实战案列&#xff0c;带你深入理解这三者的设计思想、使用场景以及闭…...

ORACLE 11.2.0.4 数据库磁盘空间爆满导致GAP产生

前言 昨天晚上深夜接到客户电话&#xff0c;反应数据库无法正常使用&#xff0c;想进入服务器检查时&#xff0c;登录响应非常慢。等两分钟后进入服务器且通过sqlplus进入数据库也很慢。通过检查服务器磁盘空间发现数据库所在区已经爆满&#xff0c;导致数据库在运行期间新增审…...

面试题总结一

第一天 1. 快速排序 public class QuickSort {public static void quickSort(int[] arr, int low, int high) {if (low < high) {// 分区操作&#xff0c;获取基准元素的最终位置int pivotIndex partition(arr, low, high);// 递归排序基准元素左边的部分quickSort(arr, …...

SWUST数据结构下半期实验练习题

1068: 图的按录入顺序深度优先搜索 #include"iostream" using namespace std; #include"cstring" int visited[100]; char s[100]; int a[100][100]; int n; void dfs(int k,int n) {if(visited[k]0){visited[k]1;cout<<s[k];for(int i0;i<n;i){i…...

专业版降重指南:如何用Python批量替换同义词?自动化操作不香嘛?

还在手动一个个改词降重&#xff1f;&#x1f440; 是兄弟就别再CtrlF了&#xff0c;来试试Python自动同义词替换批量降重法&#xff0c;简直是论文改写效率神器&#xff01; 这篇我们来一波实操干货&#xff1a; &#x1f449; 如何用Python写出一个自动替换论文关键词的脚本…...

一:操作系统之操作系统结构

深入浅出&#xff1a;一文读懂操作系统的五种核心结构 操作系统&#xff0c;作为计算机硬件与应用软件之间的桥梁&#xff0c;其内部组织结构是决定其性能、稳定性、可维护性和安全性的关键。就像建造房屋需要选择不同的建筑结构一样&#xff0c;设计操作系统也需要选择或混合…...

机器学习 Day18 Support Vector Machine ——最优美的机器学习算法

1.问题导入&#xff1a; 2.SVM定义和一些最优化理论 2.1SVM中的定义 2.1.1 定义 SVM 定义&#xff1a;SVM&#xff08;Support Vector Machine&#xff0c;支持向量机&#xff09;核心是寻找超平面将样本分成两类且间隔最大 。它功能多样&#xff0c;可用于线性或非线性分类…...

IIS入门指南:原理、部署与实战

引言&#xff1a;Web服务的基石 在Windows Server机房中&#xff0c;超过35%的企业级网站运行在IIS&#xff08;Internet Information Services&#xff09;之上。作为微软生态的核心Web服务器&#xff0c;IIS不仅支撑着ASP.NET应用的运行&#xff0c;更是Windows Server系统管…...

Linux运维——Shell脚本读取配置文件

Shell脚本读取配置文件 一、键值对格式配置文件&#xff08;最常用&#xff09;1.1、配置文件示例1.2、source命令导入1.3、sed解析1.4、解析数组 二、INI格式配置文件1.1、配置文件示例1.2、sed解析1.3、ini配置带数组&#xff08;显式声明数组&#xff09;1.4、ini配置带数组…...

答题pk小程序道具卡的获取与应用

道具卡是答题PK小程序中必不可少的一项增加趣味性的辅助应用&#xff0c;那么道具卡是如何获取与应用的呢&#xff0c;接下来我们来揭晓答案&#xff1a; 一、道具卡的获取&#xff1a; 签到获取&#xff1a;在每日签到中签到不仅可获得当日的签到奖励积分&#xff0c;同时连…...

leetcode3265. 统计近似相等数对 I-medium

1 题目&#xff1a;统计近似相等数对 I 官方标定难度&#xff1a;中 给你一个正整数数组 nums 。 如果我们执行以下操作 至多一次 可以让两个整数 x 和 y 相等&#xff0c;那么我们称这个数对是 近似相等 的&#xff1a; 选择 x 或者 y 之一&#xff0c;将这个数字中的两个…...

【架构篇】代码组织结构设计

代码组织结构设计&#xff1a;模块化分层与高效协作实践 摘要 本文以Java项目为例&#xff0c;解析后端代码组织的标准化结构&#xff0c;涵盖模块划分原则、依赖管理策略及实际应用场景。通过模块化设计提升代码可维护性、团队协作效率及系统扩展能力。 一、模块化设计的核心…...

2_Spring【IOC容器中获取组件Bean】

Spring中IOC容器中获取组件Bean 实体类 //接口 public interface TestDemo {public void doSomething(); } // 实现类 public class HappyComponent implements TestDemo {public void doSomething() {System.out.println("HappyComponent is doing something...")…...

日期数据渲染转换问题

今天在学习Springboot框架时&#xff0c;想做一个非常简单的增删改查巩固一下&#xff0c;结果在数据渲染上出现了一个小问题&#xff0c;如图数据库中的数据一切正常 但是在前端渲染时&#xff0c;是下面这个效果 这是因为数据库存储的日期类型数据在前端渲染时&#xff0c;没…...

Spring Boot拦截器详解:原理、实现与应用场景

精心整理了最新的面试资料和简历模板&#xff0c;有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 一、拦截器概述 拦截器&#xff08;Interceptor&#xff09;是Spring MVC框架中用于对请求进行预处理和后处理的组件&#xff0c;主要作用于Controller层。相…...

ubuntu18.04编译qt5.14.2源码

ubuntu18.04编译qt5.14.2源码 文章目录 ubuntu18.04编译qt5.14.2源码[toc]1 前言2 参考文档3 下载源码3.1 方法13.2 方法23.3 方法3 4 ubuntu编译qt源码4.1 环境准备4.2 设置交换分区大小4.3 编译源码4.4 添加环境变量4.5 验证编译结果4.6 编译帮助文档&#xff08;qch&#xf…...

创建指定版本的vite项目

1、获取vite的版本号 npm view create-vite versions 注:4.4.1版本即对应着node16版本的项目 2、创建制定版本的vite项目 npm init vite<version>...

iOS 初识RunLoop

iOS 初识RunLoop 文章目录 iOS 初识RunLoopRunLoop的概念RunLoop的功能RunLoop和线程的关系RunLoop的结构ModeObserverTimer 和 source小结 RunLoop的核心RunLoop的流程RunLoop的应用AutoreleasePool响应触控事件刷新界面常驻线程网络请求NSTimer 和 CADisplayLinkNSTimerGCDTi…...

电子电路仿真实验教学平台重磅上线!——深圳航天科技创新研究院倾力打造,助力高校教学数字化转型

在传统电子电路课堂中&#xff0c;实验室的灯光总与高昂的成本、拥挤的设备、反复的耗材损耗相伴&#xff0c;而教师不得不面对这样的现实&#xff1a;有限的硬件资源束缚着教学深度&#xff0c;不可逆的实验风险制约着创新探索&#xff0c;固化的时空场景阻碍着个性化学习。当…...

搭建一个WordPress网站需要多少成本

WordPress 最初可能只是一个简单的博客平台。但近年来&#xff0c;它不仅成为了最好的博客平台&#xff0c;还成为了一个全面的内容管理系统。白宫、jQuery、NGINX、《纽约时报》等企业都把 WordPress 作为自己的网上家园。 不过&#xff0c;它们只是其中的佼佼者。根据 Built…...

Python数据可视化 - Pyecharts绘图示例

文章目录 一、Pyecharts简介及安装1. Pyecharts简介2. 安装Pyecharts 二、准备数据三、饼图示例1. 初始化选项配置2. 饼图相关设置3. 全局配置项3.1 标题配置项3.2 图例配置项3.3 提示框配置项3.4 工具箱配置项3.5 视觉映射配置项 4. 系列配置项4.1 标签选项配置4.2 图元样式配…...

NC016NC017美光固态芯片NC101NC102

NC016NC017美光固态芯片NC101NC102 在存储技术的演进历程中&#xff0c;美光科技的NC016、NC017、NC101与NC102系列固态芯片&#xff0c;凭借其技术创新与市场适应性&#xff0c;成为行业关注的焦点。本文将从技术内核、产品性能、行业动向、应用场景及市场价值五个维度&#…...

[Android] 青木扫描全能文档3.0,支持自动扫描功能

声明&#xff1a;根据许多帖友的反馈&#xff0c;我也根据重新实测得出结论&#xff1a;该app是提供一天的体验时间&#xff0c;后续还是采取收费才能使用功能的措施。因为现在市面上免费使用的扫描工具很少了&#xff0c;所以当初我初步测试感觉软件不错就发布了出来&#xff…...

Vue 3 动态 ref 的使用方式(表格)

一、问题描述 先给大家简单介绍一下问题背景。我正在开发的项目中&#xff0c;有一个表格组件&#xff0c;其中一列是分镜描述&#xff0c;需要支持视频上传功能。用户可以为每一行的分镜描述上传对应的视频示例。然而&#xff0c;在实现过程中&#xff0c;出现了一个严重的问…...

Bash fork 炸弹 —— :(){ :|: };:

&#x1f9e0; 什么是 Fork 炸弹&#xff1f; Fork 炸弹是一种拒绝服务&#xff08;DoS&#xff09;攻击技术&#xff0c;利用操作系统的 fork() 系统调用不断创建新进程&#xff0c;直到系统资源&#xff08;如进程表、CPU、内存&#xff09;被耗尽&#xff0c;从而使系统无法…...

互联网大厂Java面试:从Spring Boot到微服务架构的技术深挖

场景描述 在某互联网大厂的面试会议室里&#xff0c;严肃的面试官老王正审视着面前的程序员明哥。这场面试以业务场景为切入点&#xff0c;围绕Java技术栈展开。 第一轮&#xff1a;基础知识与Spring生态 面试官老王&#xff1a; 明哥&#xff0c;你对Spring Boot的核心功能…...

IT审计之外包

外包管理的定义与重要性 外包管理是指企业将部分业务或服务委托给外部供应商进行管理和执行的过程。在IT领域&#xff0c;外包管理尤为重要&#xff0c;因为IT系统的复杂性和关键性要求企业必须确保外包服务的质量和安全性。外包管理不仅涉及合同管理&#xff0c;还包括供应商…...

精益数据分析(66/126):技术驱动的大规模用户调研——从工具组合到高效验证

精益数据分析&#xff08;66/126&#xff09;&#xff1a;技术驱动的大规模用户调研——从工具组合到高效验证 在创业的移情阶段&#xff0c;如何突破小规模访谈的局限&#xff0c;快速获取大规模用户反馈&#xff1f;今天&#xff0c;我们结合LikeBright的实战案例与《精益数…...

通俗解释Transformer在处理序列问题高效的原因(个人理解)

Transformer出现的背景 CNN 的全局关联缺陷卷积神经网络&#xff08;CNN&#xff09;通过多层堆叠扩大感受野&#xff0c;但在自然语言处理中存在本质局限&#xff1a; 局部操作的语义割裂&#xff1a;每个卷积核仅处理固定窗口&#xff08;如 3-5 词&#xff09;&#xff0c;…...