MyBatis 的延迟加载是如何实现的

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: MyBatis的延迟加载(懒加载)特性提高了性能,只在需要时加载关联数据。配置延迟加载需在`mybatis-config.xml`中设置`lazyLoadingEnabled`为`true`,`aggressiveLazyLoading`为`false`。实现原理基于代理对象,MyBatis为延迟加载属性创建代理,在访问时触发实际查询。代理通过Java动态代理实现,拦截方法调用,按需加载数据。

MyBatis 的延迟加载(懒加载)特性允许在需要使用关联对象数据时才进行加载,而不是在执行主查询时就加载所有相关数据。这种机制可以提高应用程序的性能,特别是当关联数据庞大或关联层次较深时。我们将通过以下几个方面来深入了解MyBatis的延迟加载实现机制。

配置延迟加载

要在MyBatis中启用延迟加载,需要在配置文件mybatis-config.xml中进行相关设置:

xml

代码解读

复制代码

<settings>
    <!-- 开启全局的延迟加载 -->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!-- 将积极加载改为消极加载(即延迟加载) -->
    <setting name="aggressiveLazyLoading" value="false"/>
    <!-- 当开启延迟加载时,每个属性都会延迟加载 -->
    <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>
  • lazyLoadingEnabled 控制是否启用延迟加载。
  • aggressiveLazyLoading 控制是否对所有关联对象进行加载,设置为 false 可以避免加载不必要的关联对象。
  • lazyLoadTriggerMethods 指定哪些方法触发加载属性,通常保持默认即可。

实现原理

MyBatis 的延迟加载主要依赖于代理对象。当配置了延迟加载后,MyBatis 会为需要延迟加载的属性生成一个代理对象,当访问这个属性时,代理对象负责执行实际的加载操作。

步骤概述

  1. 结果映射: 在结果映射时,对于配置了延迟加载的关联属性,MyBatis 不会立即执行关联查询,而是为该属性创建一个代理对象。
  2. 代理触发: 当访问这个属性的方法时,比如get方法,代理对象会触发实际的关联查询。
  3. 查询加载: 代理对象执行关联查询,并将查询结果设置到目标对象的属性中,替换掉自身。

代码演示

以一对多关系为例,配置延迟加载:

xml

代码解读

复制代码

<resultMap id="blogResultMap" type="Blog">
    <collection property="posts" ofType="Post" select="selectPostsForBlog" column="id" fetchType="lazy"/>
</resultMap>

<select id="selectBlog" resultMap="blogResultMap">
    SELECT * FROM blog WHERE id = #{id}
</select>

<select id="selectPostsForBlog" parameterType="int" resultType="Post">
    SELECT * FROM post WHERE blog_id = #{id}
</select>

这里,<collection> 中的 fetchType="lazy" 指示MyBatis为 posts 属性创建代理对象,以实现延迟加载。

源码解析

在MyBatis中,延迟加载的实现涉及到以下几个关键类:

  • SqlSessionManager: 作为SQL会话的管理器,它负责创建SqlSession
  • Configuration: 包含了MyBatis的所有配置信息,包括延迟加载的设置。
  • Executor: 执行器,负责执行SQL命令,延迟加载的触发最终会调用执行器来执行关联查询。
  • ProxyFactory: 代理工厂,用于创建延迟加载的代理对象。

延迟加载的代理对象主要通过Java的动态代理实现。在访问代理对象的方法时,动态代理会拦截这个调用,并判断是否需要触发延迟加载。如果需要,则执行实际的查询并加载数据,然后将结果设置到目标对象中。

以下是一个简化的示例来说明代理对象如何拦截方法调用并触发加载:

java

代码解读

复制代码

public class LazyLoadingProxy implements InvocationHandler {
    private Object target;
    private boolean loaded;

    public LazyLoadingProxy(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (!loaded && isLoadMethod(method)) {
            loadObject();
            loaded = true;
        }
        return method.invoke(target, args);
    }

    private boolean isLoadMethod(Method method) {
        // 判断方法是否触发加载
        return "getPosts".equals(method.getName());
    }

    private void loadObject() {
        // 执行加载逻辑,比如执行SQL查询
    }
}

在上面的代码中,LazyLoadingProxy 是一个动态代理类,它在方法调用时判断是否需要加载数据,并在必要时进行加载。这个简化的例子演示了延迟加载的基本思想。

总结

MyBatis的延迟加载特性通过动态代理和配置控制,实现了按需加载关联数据的能力。通过延迟加载,可以优化应用程序的性能,特别是在处理复杂关系和大量数据时。虽然延迟加载增加了实现的复杂度,但MyBatis通过提供灵活的配置和强大的映射机制,使得管理这种复杂度成为可能。


转载来源:https://juejin.cn/post/7385801028942184457

相关文章
|
6月前
|
Java 数据库连接 数据库
【Mybatis】mybatis 是否支持延迟加载?
【Mybatis】mybatis 是否支持延迟加载?
|
6月前
|
存储 缓存 Java
【MyBaits】4、延迟加载、MyBatis 的缓存
【MyBaits】4、延迟加载、MyBatis 的缓存
45 0
|
6月前
|
Java 数据库连接 mybatis
Mybatis中延迟加载~
Mybatis中延迟加载~
|
6月前
|
Java 数据库连接 mybatis
一文彻底搞懂Mybatis系列(十二)之MyBatis多对一映射延迟加载(association和lazyLoadingEnabled)
一文彻底搞懂Mybatis系列(十二)之MyBatis多对一映射延迟加载(association和lazyLoadingEnabled)
112 0
|
SQL Java 数据库连接
【MyBatis】高级映射多对一,一对多和延迟加载
【MyBatis】高级映射多对一,一对多和延迟加载
|
SQL Java 数据库连接
2021-08-06项目实现过程-ssm框架,关联映射,延迟加载,使用注解实现mybatis映射
2021-08-06项目实现过程-ssm框架,关联映射,延迟加载,使用注解实现mybatis映射
69 0
|
SQL Java 数据库连接
Mybatis 是否支持延迟加载?如果支持,它的实现原理是什么?
Mybatis 是否支持延迟加载?如果支持,它的实现原理是什么?
101 0
|
Java 数据库连接 mybatis
MyBatis 是否支持延迟加载?怎么实现?什么时候启用?
MyBatis 是否支持延迟加载?怎么实现?什么时候启用?
136 0
|
SQL 存储 XML
Mybatis 高阶学习(映射文件深入、延迟加载、缓存、注解开发等)
Mybatis 高阶学习(映射文件深入、延迟加载、缓存、注解开发等)
359 0
Mybatis 高阶学习(映射文件深入、延迟加载、缓存、注解开发等)
|
SQL Java 数据库连接
Java 最常见的面试题:mybatis 是否支持延迟加载?延迟加载的原理是什么?
Java 最常见的面试题:mybatis 是否支持延迟加载?延迟加载的原理是什么?