mybatis 是否支持延迟加载?延迟加载的原理是什么?

1. MyBatis 是否支持延迟加载?

是的,MyBatis 支持延迟加载。延迟加载的主要功能是推迟数据加载的时机,直到真正需要时再去加载。这种方式能提高性能,尤其是在处理关系型数据时,可以避免不必要的数据库查询。

具体来说,MyBatis 支持在关联对象(association)和关联集合(collection)上进行延迟加载。通常,association 用于一对一的关联查询,collection 用于一对多的关联查询。

配置延迟加载

要启用延迟加载功能,您需要在 MyBatis 的配置文件中设置 lazyLoadingEnabledtrue

XML 复制代码
<settings>
    <setting name="lazyLoadingEnabled" value="true"/>
</settings>

通过这种方式,MyBatis 在查询主表数据时,关联表的数据不会立即加载,而是等到访问关联属性时再去查询。

下面来详细说明一下:

举例:

假设有两个表 UserAddress,它们之间有一对一的关系,一个用户对应一个地址。

java 复制代码
public class User {
    private Integer id;
    private String name;
    private Address address; // 延迟加载
    // getters and setters
}

public class Address {
    private Integer id;
    private String street;
    // getters and setters
}

如果在 User 类中的 address 属性上启用延迟加载,则在查询 User 时,address 这一关联数据不会立即加载,而是等到我们访问 address 时才会去查询 Address 表。

2. 表结构的关系

User 类和 Address 类代表了数据库中的两张表,User 表和 Address 表。在实际的数据库设计中,User 表和 Address 表之间通常会有外键关联,例如 Address 表可能会有一个字段 user_id,用来表示 AddressUser 的一对一关系。

假设我们的数据库表结构如下:

  • User 表

    复制代码
    CREATE TABLE user (
        id INT PRIMARY KEY,
        name VARCHAR(100)
    );
  • Address 表

    复制代码
    CREATE TABLE address (
        id INT PRIMARY KEY,
        street VARCHAR(100),
        user_id INT,  -- 关联到 User 表
        FOREIGN KEY (user_id) REFERENCES user(id)
    );

这里,Address 表中的 user_id 字段是一个外键(即使数据库表没有外键约束,MyBatis 依然可以根据配置的 SQL 查询进行延迟加载。外键约束只是保证了数据完整性,并不影响 MyBatis 如何进行延迟加载。),指向 User 表中的 id 字段,表示每个地址属于某个用户。

3. MyBatis 中如何关联表

在 MyBatis 中,User 类的 address 属性是延迟加载的,即当我们访问 user.getAddress() 时,MyBatis 会根据 user_id 来查询 Address 表中的数据。这是通过 MyBatis 的映射配置 来实现的。

MyBatis 映射配置

在 MyBatis 中,我们可以通过 映射文件(Mapper XML)注解 来指定如何加载 UserAddress 之间的关联数据。

假设我们使用的是 XML 配置,可能会在 User 类和 Address 类之间进行关联配置。

例如,定义一个查询 User 对象时,同时懒加载它的 Address 属性:

复制代码
<!-- UserMapper.xml -->
<resultMap id="userResultMap" type="User">
    <id property="id" column="id"/>
    <result property="name" column="name"/>
    <!-- 延迟加载 address -->
    <association property="address" column="id" select="selectAddressByUserId" fetchType="lazy"/>
</resultMap>

<select id="getUserById" resultMap="userResultMap">
    SELECT id, name FROM user WHERE id = #{id}
</select>

<!-- 查询 address -->
<select id="selectAddressByUserId" resultType="Address">
    SELECT * FROM address WHERE user_id = #{userId}
</select>

在这里:

  • resultMap 配置了如何将数据库查询结果映射到 User 对象。address 属性是通过关联查询来获取的(association)。
  • selectAddressByUserId 这个 SQL 查询通过 user_id 字段来查找关联的 Address 数据。

4. 延迟加载的实际流程

  • 当你查询 User 对象时(例如 SELECT id, name FROM user WHERE id = #{id}),只会查询 User 表,address 字段不会被立即加载。
  • User 对象被加载后,如果你访问 user.getAddress(),MyBatis 会检查 address 是否已经加载。如果没有加载,MyBatis 会发起一个新的查询,查询与当前 user 关联的 Address 数据。

具体来说,代理对象会拦截你对 user.getAddress() 的调用,然后执行 selectAddressByUserId 查询:

复制代码
SELECT * FROM address WHERE user_id = #{userId}

#{userId} 会被替换为你查询的 User 对象的 id,然后执行查询,返回的 Address 对象会被设置到 User 对象的 address 属性中。

5. 总结:

  • 在数据库中,Address 表通过 user_id 字段与 User 表关联。
  • MyBatis 在映射文件中配置了 UserAddress 之间的关系,并且配置了延迟加载。
  • 初次查询 User 数据时,只会查询 User 表的数据,address 不会立即加载。
  • 当你访问 user.getAddress() 时,MyBatis 会触发一个新的查询(SELECT * FROM address WHERE user_id = #{userId}),加载 Address 数据并返回给你。

因此,SELECT * FROM address WHERE user_id = #{userId} 这个查询是由 MyBatis 根据 User 对象的 id 字段动态生成的,目的是通过外键 user_id 查询到与该 User 对象关联的 Address 数据。这是通过映射文件中的 association 和延迟加载配置来实现的。

相关推荐
okseekw12 分钟前
Java 字符串三巨头:String、StringBuilder、StringJoiner —— 初学者避坑指南 🤯
java
毕设源码余学姐23 分钟前
计算机毕设 java 中医药药材分类采购网站 SSM 框架药材交易平台 Java 开发的分类采购与订单管理系统
java·开发语言·课程设计
BD_Marathon28 分钟前
【JUC】并发与并行
java
okseekw40 分钟前
Java String类详解:不可变性、创建方式与比较方法
java
q***649741 分钟前
Spring Boot 各种事务操作实战(自动回滚、手动回滚、部分回滚)
java·数据库·spring boot
降临-max1 小时前
JavaSE---网络编程
java·开发语言·网络·笔记·学习
带刺的坐椅1 小时前
Solon AI 开发学习5 - chat - 支持哪些模型?及方言定制
java·ai·openai·solon
悟空码字2 小时前
单点登录:一次登录,全网通行
java·后端
傻啦嘿哟2 小时前
物流爬虫实战:某丰快递信息实时追踪技术全解析
java·开发语言·数据库
倚肆2 小时前
Spring Boot Security 全面详解与实战指南
java·spring boot·后端