首页 > 其他分享 >Mybatis 延迟加载的实现原理

Mybatis 延迟加载的实现原理

时间:2024-11-08 09:19:11浏览次数:6  
标签:对象 代理 查询 MyBatis Mybatis 加载 延迟

一、MyBatis 延迟加载的支持

1. 延迟加载的配置

在 MyBatis 中,延迟加载可以通过全局配置和局部配置来实现:

  1. 全局配置:可以在 MyBatis 的配置文件中进行设置,控制全局的延迟加载行为。

    <configuration>
        <settings>
            <setting name="lazyLoadingEnabled" value="true"/>
            <setting name="aggressiveLazyLoading" value="false"/>
        </settings>
    </configuration>
    
    • lazyLoadingEnabled:设置为 true 表示开启延迟加载,默认为 false
    • aggressiveLazyLoading:设置为 false 表示只有在访问某个延迟加载属性时,才会触发加载。如果设置为 true,则一旦调用了延迟加载的对象中的任意一个属性,所有延迟加载的属性都会被加载,默认为 false
  2. 局部配置:可以在 ResultMap 中指定具体的映射关系是否需要延迟加载。

    <resultMap id="UserResultMap" type="User">
        <id property="id" column="user_id"/>
        <result property="name" column="user_name"/>
        <association property="address" javaType="Address" column="address_id" select="selectAddressById" lazy="true"/>
    </resultMap>
    
    • lazy="true":表示该关联属性(如 address)采用延迟加载。
2. 延迟加载的对象关系

MyBatis 支持对一对一(association)和一对多(collection)的映射进行延迟加载。典型场景如下:

  • 一对一:用户表和地址表之间的关系,用户的地址信息可以在需要时才加载。
  • 一对多:用户和订单之间的关系,用户的订单列表可以在访问时才加载。

二、MyBatis 延迟加载的实现原理

MyBatis 的延迟加载实现基于动态代理机制(Dynamic Proxy)和 CGLIB 代理。具体来说,当 MyBatis 在处理需要延迟加载的属性时,会为这些属性生成一个代理对象,这个代理对象在被实际访问时才会触发数据库查询,加载真实的数据。

1. 动态代理机制

MyBatis 使用 Java 动态代理或 CGLIB 来实现延迟加载,主要依赖以下几个核心组件:

  1. 代理对象:MyBatis 为延迟加载的属性创建代理对象,这个代理对象并不包含实际的数据,而是仅仅记录下要执行的 SQL 语句及其参数。

  2. Invoker 接口:这是 MyBatis 内部的一个接口,用于执行代理对象的延迟加载逻辑。它封装了 SQL 的执行和结果的返回。

  3. 延迟加载触发器:当代理对象的属性被访问时,触发器启动,调用 Invoker 接口,执行延迟加载的 SQL 语句,从数据库中获取数据并填充到原始对象中。

2. 实际执行过程

以下是延迟加载的实际执行过程:

  1. 代理对象的创建

    • 当 MyBatis 解析 ResultMap 并发现某个属性配置了 lazy="true",它会在加载这个对象时,为该属性创建一个代理对象。这个代理对象可以是一个 Java 动态代理(基于接口的)或者是 CGLIB 代理(基于子类的)。
  2. 延迟加载的触发

    • 当应用程序首次访问该代理对象的属性时,例如调用 user.getAddress(),MyBatis 通过代理机制捕获这个访问请求。
  3. 查询执行

    • 代理对象的 Invoker 接口在捕获到访问请求后,立即执行预先定义好的 SQL 查询,从数据库中获取实际的数据。
  4. 结果填充

    • 查询结果返回后,MyBatis 将结果映射到目标对象(如 Address),并填充到原始对象的相应属性中。
  5. 对象替换

    • 在延迟加载完成后,MyBatis 会将代理对象替换为实际的查询结果对象,后续对该属性的访问将直接返回已经加载的数据,而不会再次触发延迟加载。

三、延迟加载的优缺点

1. 优点
  1. 性能优化:延迟加载可以减少不必要的数据库查询操作,尤其是在对象关联关系复杂的场景下,通过按需加载减少数据库的压力。

  2. 资源节省:避免一次性加载大量不必要的数据,从而节省内存和网络资源。

  3. 灵活性高:开发者可以根据实际需要选择性地为某些关联属性启用延迟加载,从而精细化控制数据加载行为。

2. 缺点
  1. 实现复杂:延迟加载的实现涉及动态代理、SQL 执行控制等机制,增加了系统的复杂性,可能导致调试困难。

  2. 潜在性能隐患:如果延迟加载没有妥善处理,可能会导致“n+1 查询问题”,即在加载主对象时,需要反复执行查询以加载关联对象,造成性能瓶颈。

  3. 开发者需注意加载时机:错误地使用延迟加载可能导致延迟加载对象未被正确加载,尤其是在 Session 生命周期管理不当的情况下。

四、延迟加载的最佳实践

  1. 选择性使用延迟加载:不要盲目地为所有关联关系启用延迟加载,应根据业务场景的需求,选择性地在需要优化性能的地方使用。

  2. 小心 n+1 查询问题:在使用一对多的延迟加载时,要特别小心 n+1 查询问题。如果可能存在大量的子对象关联查询,应考虑使用 JOIN 查询或 ResultMap 配置进行一次性加载。

  3. Session 生命周期管理:确保延迟加载的触发在 MyBatis SqlSession 生命周期内进行,否则可能会引发 SqlSession 关闭后无法加载数据的异常。

  4. 结合 aggressiveLazyLoading 进行优化:根据实际需求调整 aggressiveLazyLoading 配置,在需要时提前加载关联数据,减少多次 SQL 查询的开销。

  5. 使用缓存:可以结合 MyBatis 的二级缓存来缓存延迟加载的结果,进一步提升性能。

五、总结

MyBatis 通过动态代理机制实现了灵活的延迟加载功能,为开发者提供了在复杂对象关系映射中优化数据库访问的手段。尽管延迟加载可以显著减少不必要的数据库查询,但也需要谨慎使用,避免潜在的性能问题。通过合理配置和良好的实践,MyBatis 的延迟加载可以在保持代码简洁性的同时,大幅度提升系统性能。

标签:对象,代理,查询,MyBatis,Mybatis,加载,延迟
From: https://blog.csdn.net/Flying_Fish_roe/article/details/143613079

相关文章

  • 【客户投诉系统】 Sringboot+vue+soap+activiti+mybatis+element-ui
    [!NOTE]分享课程系统,客户平台投诉系统主要框架:Springboot,mybatis,Activiti,soap,Element-UI,Vue主要功能:用户可以对不同的平台,例如美团、学习通、饿了么等进行投诉(Springboot,mybatis),工作管理员会对该投诉信息进行审批(Activiti),若审批通过,通过soap服务传递给对应......
  • CC-ADMIN后台简介一个基于 Spring Boot 2.1.3 、SpringBootMybatis plus、JWT、Shiro
    说明此文章为转发的,方便日后查看。系统演示环境http://www.cc-admin.top/#/home简介CC-ADMIN前端简介现在市面的上后台管理系统很多,不差你这一个,为啥又来个轮子?答:材料不一样。本轮子的选材是在考察过antv、element之后选择了quasar,前两个很优秀,尤其是antv的外观我特......
  • Mybatis框架入门
    IDEA使用Maven部署第一个MyBatis项目,两种方法导入,一个是Jar包的形式,此形式用于初学者学习并完成学校实训作业,第二种则是通过pom.xml文件引入依赖从而避免了从官网下载jar包等问题。一、创建一个Maven工程:File-->New-->projcet-->Maven二、导入以下Jar包:New-->ProjcetStruc......
  • Vue3 - 详细实现虚拟列表前端虚拟滚动列表解决方案,vue3长列表优化之虚拟列表,解决列表
    前言Vue2版本,请访问这篇文章在vue3项目开发中,详解实现虚拟列表高度不固定(不定高)且复杂含有图片视频等复杂虚拟列表教程,决列表每项高度不确定及img图像或视频的加载方案,利用缓冲区技术解决用户浏览时渲染不及时列表闪烁白屏/列表加载闪屏,解vue3实现虚拟列表优化大......
  • 深入解析 WKWebView 的 didFinish 回调时机:页面加载与异步操作的处理
    在iOS开发中,我们经常会用WKWebView来加载和展示H5页面。通常,开发者会在WKWebView的didFinish方法中处理页面加载完成后的逻辑,例如更新UI或执行后续操作。然而,didFinish的触发时机并不总是如我们所期待,它并不会等待所有异步操作(如AJAX请求、图片加载等)完成后再执行......
  • IntersectionObserver实现H5表格触底加载
    <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"/><metaname="viewport"content="width=device-width,initial-scale=1.0"/><title>Document</title&g......
  • 十一 MyBatis查询语句专题
    十一、MyBatis查询语句专题模块名:mybatis-007-select打包方式:jar引入依赖:mysql驱动依赖、mybatis依赖、logback依赖、junit依赖。引入配置文件:jdbc.properties、mybatis-config.xml、logback.xml创建pojo类:Car创建Mapper接口:CarMapper创建Mapper接口对应的映射文件:co......
  • 十五 MyBatis的逆向工程
    十五、MyBatis的逆向工程所谓的逆向工程是:根据数据库表逆向生成Java的pojo类,SqlMapper.xml文件,以及Mapper接口类等。要完成这个工作,需要借助别人写好的逆向工程插件。思考:使用这个插件的话,需要给这个插件配置哪些信息?pojo类名、包名以及生成位置。SqlMapper.xml文件名以......
  • 十四 MyBatis的缓存
    十四、MyBatis的缓存缓存:cache缓存的作用:通过减少IO的方式,来提高程序的执行效率。mybatis的缓存:将select语句的查询结果放到缓存(内存)当中,下一次还是这条select语句的话,直接从缓存中取,不再查数据库。一方面是减少了IO。另一方面不再执行繁琐的查找算法。效率大大提升。my......
  • 十三 MyBatis的高级映射及延迟加载
    十三、MyBatis的高级映射及延迟加载模块名:mybatis-009-advanced-mapping打包方式:jar依赖:mybatis依赖、mysql驱动依赖、junit依赖、logback依赖配置文件:mybatis-config.xml、logback.xml、jdbc.properties拷贝工具类:SqlSessionUtil准备数据库表:一个班级对应多个学生。......