1. MyBatis 是否支持延迟加载?
是的,MyBatis 支持延迟加载。延迟加载的主要功能是推迟数据加载的时机,直到真正需要时再去加载。这种方式能提高性能,尤其是在处理关系型数据时,可以避免不必要的数据库查询。
具体来说,MyBatis 支持在关联对象(association
)和关联集合(collection
)上进行延迟加载。通常,association
用于一对一的关联查询,collection
用于一对多的关联查询。
配置延迟加载
要启用延迟加载功能,您需要在 MyBatis 的配置文件中设置 lazyLoadingEnabled
为 true
。
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
通过这种方式,MyBatis 在查询主表数据时,关联表的数据不会立即加载,而是等到访问关联属性时再去查询。
下面来详细说明一下:
举例:
假设有两个表 User
和 Address
,它们之间有一对一的关系,一个用户对应一个地址。
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
,用来表示 Address
和 User
的一对一关系。
假设我们的数据库表结构如下:
-
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) 或 注解 来指定如何加载 User
和 Address
之间的关联数据。
假设我们使用的是 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 在映射文件中配置了
User
和Address
之间的关系,并且配置了延迟加载。 - 初次查询
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
和延迟加载配置来实现的。