MyBatis的延迟加载

  问题:在一对多的关系中,例:有一个班级,其中有100个学生,在查询班级的时候要不要把关联的学生查询出来,查询学生的时候要不要把关联的班级查询出来?
  解答:在查询班级的时候,学生的信息应该是什么时候使用什么时候去查询,在查询学生时,班级的信息应该是随着学生查询时一起查询出来。

一、延迟加载

  1. 概念:MyBatis中的延迟加载也称为懒加载,是指在进行表的关联查询时,按照设置延迟规则推迟对关联对象的select查询。在真正使用数据的时候才发起查询,不用的时候不查询关联的数据,延迟加载又叫做按需查询。例如,在进行一对多查询的时候,只查询出一方,当程序中需要多方数据时,MyBatis在发出sql语句进行查询,这样子延迟加载就可以减少数据库压力,MyBatis的延迟加载只是对关联对象的查询有延迟设置,对于主加载对象都是直接执行查询语句的。

  2. MyBatis中延迟加载的条件:resultMap可以实现高级映射,例:使用association、collection实现一对一及一对多映射,association、collection具备延迟加载功能。

  3. 延迟加载的好处:先从单表查询,需要时再从关联表查询,大大提高数据库性能,因为查询单表比关联查询多张表速度要快。

  4. 使用场景:在对应的四种关系表中,一对多、多对多通常情况下采用延迟加载,多对一、一对一、通常采用立即加载。

  5. 延迟加载的应用要求:关联对象的查询与主加载对象的查询必须是分别进行的select语句,不能是使用多表连接所进行的select查询,因为多表连接查询,实质是对一张表的查询,对由多个表连接后形成的一张表的查询,会一次性将多张表的所有信息查询出来。

二、开启延迟加载功能

  MyBatis中实现查询方法的延迟加载,在MyBatis
的配置文件中通过设置settings的lazyLoadingEnabled属性为true进行开启全局的延迟加载,通过aggressiveLazyLoading属性开启立即加载。

设置名 描述 有效值 默认值
lazyLoadingEnabled 延迟加载的全局开关,当开启时所有关联对象都会延迟加载,特定关联关系可以通过设置fetchType属性来覆盖该项的开关状态。 true|false false
aggressiveLazyLoading 开启时,任一方法的调用都会加载该对象的所有延迟加载属性。 否则,每个延迟加载属性会按需加载(参考 lazyLoadTriggerMethods)。 true|false false(在3.4.1及之前的版本默认值为true)
lazyLoadTriggerMethods 指定对象的哪些方法触发一次延迟加载。 用逗号分隔的方法列表。 equals,clone,hashCode,toString
<settings> <!-- 开启延迟加载主要是前两个配置--> <!-- 延迟加载,默认是false--> <setting name="lazyLoadingEnabled" value="true" /> <!-- 当为true时,所有延迟属性都会立即加载,为false时,调用这些延迟属性时才会查询和加载--> <setting name="aggressiveLazyLoading" value="false" /> <!-- 最好配置为空,这样可以最大限度延迟加载--> <!-- 当前配置的意思为当调用getId时延迟加载--> <!-- 可以不配置--> <setting name="lazyLoadTriggerMethods" value="getId"/> </settings>

三、延迟加载的实现

  1. 在resultMap中使用association或者collection,即可使用延迟加载。

  2. 延迟加载需要多个select语句,不能是一条多表连接的select语句。

实现班级学生案例:

  1. 创建实体类 班级类以及学生类
班级类: public class Clazz { private int id; private String name; private List<Student> students; @Override public String toString() { return "Clazz{" + "id=" + id + ", name='" + name + '\'' + ", students=" + students + '}'; } getset方法省略... 学生类: public class Student { private int id; private String name; private String sex; private int clazz; @Override public String toString() { return "Student{" + "id=" + id + ", name='" + name + '\'' + ", sex='" + sex + '\'' + ", clazz=" + clazz + '}'; } getset方法省略...
  1. 创建StudentMapper和ClazzMapper接口
ClazzMapper接口: public interface ClazzMapper { /** * 根据班级编号查询班级 * @param id * @return */ Clazz selectById(int id); } StudentMapper接口: public interface StudentMapper { /** * 根据学生编号查找学生 * @param id * @return */ Student selectById(int id); /** * 根据学生的班级号查找学生 * @param id * @return */ List<Student> selectByClazz(int id); }
  1. 创建ClazzMapper.xml和StudentMapper.xml
ClazzMapper.xml: <!-- 根据班级编号查找班级--> <select id="selectById" resultMap="rm"> select * from clazz where id=#{id} </select> <!-- 配置映射,根据学生班级号查找学生放进班级里--> <resultMap id="rm" type="clazz" autoMapping="true"> <id column="id" property="id"></id> <collection property="students" column="id" select="dao.StudentMapper.selectByClazz"></collection> </resultMap> StudentMapper.xml: <!-- 根据学生id查找学生--> <select id="selectById" resultType="student"> select * from student where id=#{id} </select> <!-- 根据学生班级号查找学生--> <select id="selectByClazz" resultType="student"> select * from student where clazz=#{id} </select>
  1. 测试:
public class Test { public static void main(String[] args) { Clazz clazz = new ClazzService().selectById(1); // 1 System.out.println(clazz.getId()); // 2 System.out.println(clazz.getName()); // 3 System.out.println(clazz.getStudents()); // 4 } }

当注释掉第4句时,因为没有要求查找学生,按照延迟加载的特性,程序只会查询班级的信息,而不会查询学生的信息,所以只有一条sql语句,就是根据班级编号查找班级的select,并没有查找学生的select:

当放开第四句时,因为clazz.getStudents()需要student数据,所以会执行第二条sql语句将student的信息查询到:


__EOF__

本文作者逍遥客灬
本文链接https://www.cnblogs.com/zbh355376/p/14986307.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   逍遥客灬  阅读(2306)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示