Mybatis 级联查询
MyBatis 的级联查询(Cascade Query)是指在一个查询中,通过关联多个表,将查询结果映射到包含嵌套对象的复杂数据结构中。MyBatis 提供了强大的级联查询支持,可以通过 resultMap
和 association
、collection
等标签来实现。
下面我们详细讲解 MyBatis 中级联查询的使用方法。
1. 一对一关联(association
)
一对一关联是指一个对象中包含另一个对象的引用。例如,一个 User
对象中包含一个 Address
对象。
实体类
public class User {
private int id;
private String name;
private int age;
private Address address; // 一对一关联
// getters and setters
}
public class Address {
private String city;
private String street;
// getters and setters
}
Mapper 接口
public interface UserMapper {
User selectUserWithAddressById(int id);
}
Mapper XML 文件
<resultMap id="UserResultMap" type="User">
<id property="id" column="id" />
<result property="name" column="name" />
<result property="age" column="age" />
<!-- 一对一关联 -->
<association property="address" javaType="Address">
<result property="city" column="city" />
<result property="street" column="street" />
</association>
</resultMap>
<select id="selectUserWithAddressById" resultMap="UserResultMap">
SELECT u.id, u.name, u.age, a.city, a.street
FROM user u
LEFT JOIN address a ON u.id = a.user_id
WHERE u.id = #{id}
</select>
association
:用于映射一对一关联。property="address"
:表示User
对象中的address
属性。javaType="Address"
:表示address
属性的类型是Address
。- 查询结果中的
city
和street
列会映射到Address
对象的属性中。
2. 一对多关联(collection
)
一对多关联是指一个对象中包含另一个对象的集合。例如,一个 User
对象中包含多个 Order
对象。
实体类
public class User {
private int id;
private String name;
private int age;
private List<Order> orders; // 一对多关联
// getters and setters
}
public class Order {
private int id;
private String orderNo;
private double amount;
// getters and setters
}
Mapper 接口
public interface UserMapper {
User selectUserWithOrdersById(int id);
}
Mapper XML 文件
<resultMap id="UserWithOrdersResultMap" type="User">
<id property="id" column="id" />
<result property="name" column="name" />
<result property="age" column="age" />
<!-- 一对多关联 -->
<collection property="orders" ofType="Order">
<id property="id" column="order_id" />
<result property="orderNo" column="order_no" />
<result property="amount" column="amount" />
</collection>
</resultMap>
<select id="selectUserWithOrdersById" resultMap="UserWithOrdersResultMap">
SELECT u.id, u.name, u.age, o.id AS order_id, o.order_no, o.amount
FROM user u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.id = #{id}
</select>
collection
:用于映射一对多关联。property="orders"
:表示User
对象中的orders
属性。ofType="Order"
:表示orders
集合中的元素类型是Order
。- 查询结果中的
order_id
、order_no
和amount
列会映射到Order
对象的属性中,并添加到orders
集合中。
3. 多级嵌套关联
多级嵌套关联是指一个对象中包含另一个对象,而另一个对象又包含其他对象。例如,一个 User
对象中包含 Address
对象,而 Address
对象又包含 Country
对象。
实体类
public class User {
private int id;
private String name;
private int age;
private Address address; // 一对一关联
// getters and setters
}
public class Address {
private String city;
private String street;
private Country country; // 一对一关联
// getters and setters
}
public class Country {
private String name;
private String code;
// getters and setters
}
Mapper 接口
public interface UserMapper {
User selectUserWithAddressAndCountryById(int id);
}
Mapper XML 文件
<resultMap id="UserWithAddressAndCountryResultMap" type="User">
<id property="id" column="id" />
<result property="name" column="name" />
<result property="age" column="age" />
<!-- 一对一关联 -->
<association property="address" javaType="Address">
<result property="city" column="city" />
<result property="street" column="street" />
<!-- 嵌套一对一关联 -->
<association property="country" javaType="Country">
<result property="name" column="country_name" />
<result property="code" column="country_code" />
</association>
</association>
</resultMap>
<select id="selectUserWithAddressAndCountryById" resultMap="UserWithAddressAndCountryResultMap">
SELECT u.id, u.name, u.age, a.city, a.street, c.name AS country_name, c.code AS country_code
FROM user u
LEFT JOIN address a ON u.id = a.user_id
LEFT JOIN country c ON a.country_id = c.id
WHERE u.id = #{id}
</select>
- 多级嵌套关联通过嵌套的
association
实现。 - 查询结果中的
country_name
和country_code
列会映射到Country
对象的属性中。
4. 延迟加载(Lazy Loading)
当级联查询的嵌套对象较多时,可以使用延迟加载来优化性能。延迟加载是指在需要时才加载嵌套对象的数据。
配置延迟加载
在 MyBatis 配置文件中启用延迟加载:
<settings>
<setting name="lazyLoadingEnabled" value="true" />
<setting name="aggressiveLazyLoading" value="false" />
</settings>
使用延迟加载
在 association
或 collection
标签中设置 fetchType="lazy"
。
<resultMap id="UserWithOrdersResultMap" type="User">
<id property="id" column="id" />
<result property="name" column="name" />
<result property="age" column="age" />
<!-- 延迟加载 orders -->
<collection property="orders" ofType="Order" fetchType="lazy">
<id property="id" column="order_id" />
<result property="orderNo" column="order_no" />
<result property="amount" column="amount" />
</collection>
</resultMap>
fetchType="lazy"
:表示延迟加载orders
集合。- 只有在访问
user.getOrders()
时,才会执行加载orders
的查询。
总结
- 一对一关联:使用
association
标签。 - 一对多关联:使用
collection
标签。 - 多级嵌套关联:通过嵌套的
association
或collection
实现。 - 延迟加载:通过配置
fetchType="lazy"
实现,优化性能。
通过合理使用级联查询,可以轻松处理复杂的对象关系映射,并提高查询效率。
要是想图省事儿,这样也可以,1对多性能不好,每一条主表数据都会再通过一条sql查询子表数据
<resultMap id="one2manyMap" type="com.study.mybatis.dto.ItemWithSku">
<id column="id" property="id" jdbcType="BIGINT"/>
<result column="code" property="code" jdbcType="VARCHAR"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
<collection property="skus"
column="id"
javaType="ArrayList"
ofType="com.study.mybatis.dto.ItemWithSku$Sku"
select="getSkusByItemId"
/>
</resultMap>
<!-- 先查主表,以主表分页就不会有分页问题 -->
<select id="findItemAndSku" resultMap="one2manyMap">
select a.id, a.code, a.name from t_item a
</select>
<!-- 再根据主表查询子表 -->
<select id="getSkusByItemId" resultType="com.study.mybatis.dto.ItemWithSku$Sku">
select a.id, a.code, a.name from t_sku a where a.item_id = #{id}
</select>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具