MyBatis 多表查询三种最常见的写法
前言:一张关联表,让你头秃了吗?
你是不是也写过这种需求:
- 查询某个用户及其角色列表
- 查询订单及明细
- 查询项目及其下属的多个阶段和负责人
最后写了一堆复杂 SQL + resultMap,运行一看,要么数据重复、要么数据丢失,最惨还可能触发 N+1 查询……
其实问题不是 MyBatis 不行,而是你用的方法不对。
🔍 三种最常见的写法
✅ 方式一:联表查询 + 扁平映射(推荐)
这是我最常用也最稳定的一种方式:写一条联表 SQL,把需要的字段都查出来,返回扁平结构,再在 Java 层进行组装。
示例 SQL:
SELECT u.id AS userId, u.name AS userName,
r.id AS roleId, r.name AS roleName
FROM user u
LEFT JOIN user_role ur ON u.id = ur.user_id
LEFT JOIN role r ON ur.role_id = r.id特点:
- 一条 SQL 查全所有数据;
- 性能高,逻辑直观;
- 可与分页插件(如 PageHelper)完美配合。
我的建议:
Java 层用 Map<Long, UserDTO> 分组封装,适合在 Service 层统一做聚合逻辑。
⚙️ 方式二:嵌套结果(resultMap + collection)
适合结构较为清晰的“树状结构”,比如订单和订单项、项目和子模块。
示例 XML:
<resultMap id="userMap" type="User">
<id property="id" column="user_id"/>
<result property="name" column="user_name"/>
<collection property="roles" ofType="Role">
<id property="id" column="role_id"/>
<result property="name" column="role_name"/>
</collection>
</resultMap>特点:
- 多表映射层级清晰;
- 比较适合中小型数据量。
踩坑经验:
- 写错列名字段,就会导致内层集合全是 null;
- 出现重复数据时,要手动去重或用 Set;
- 不适合配合分页,容易导致“分页的是主表,但集合是全量”。
🧩 方式三:嵌套查询(nested select)
适合逻辑解耦,按模块维护的场景。
示例 XML:
<collection property="roles" ofType="Role" select="selectRolesByUserId" column="id"/>
特点:
- 每条主表数据触发一次副查询;
- 易维护但 极易 N+1;
- 不适合大批量数据查询。
实战建议:
除非你能保证每次最多查询 10 条主记录,否则慎用。性能瓶颈很容易出现在这里!
📉 你可能踩过的坑
| 问题 | 症状 | 原因 | 建议 |
|---|---|---|---|
| 查询结果为 null | 子集合没数据 | 字段名或别名不匹配 | 显式写 column 属性或使用 @Results 映射 |
| 一对多重复数据 | 主表字段重复出现 | 联表未分组 / Java 封装没处理 | 手动分组聚合,避免直接用 List |
| 分页异常 | 只分页主表,子表数据混乱 | 不支持嵌套分页 | 联表 + 扁平查询是最佳方案 |
| 查询慢到爆炸 | N+1 查询 | 每条主记录触发一次 select | 转成 join 联查或改为批量查 |
✅ 实战建议:如何选择这三种方式?
| 类型 | 性能 | 可维护性 | 适合场景 |
|---|---|---|---|
| 联表扁平查询 | ⭐⭐⭐⭐⭐ | ⭐⭐ | 大批量、一对多、分页场景 |
| 嵌套结果 resultMap | ⭐⭐⭐ | ⭐⭐⭐⭐ | 结构清晰、数据量适中 |
| 子查询 nested | ⭐⭐ | ⭐⭐⭐⭐⭐ | 小数据量、逻辑独立场景 |
📦 我的最佳实践模板(真实项目用的)
- DAO 层只查数据,不做结构组装;
- Service 层按业务模型拼装 DTO;
- 多表结果不要直接给前端,统一封装响应结构;
- DTO + Builder 模式 + Map 分组,灵活好用;
📌 总结一句话:
多表查询选对方式,写代码少掉一半 bug。
不必纠结哪种方式最“完美”,关键是是否适合你当前场景。
记住:能用联查查全的,就别搞子查询;分页场景尽量别用嵌套结构;小数据就图方便,结构优先。
到此这篇关于MyBatis 多表查询的文章就介绍到这了,更多相关MyBatis 多表查询内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
Maven编译报错:未与 -source 8 一起设置引导类路径的完美解决方案
这篇文章主要为大家详细介绍了Maven编译报错:未与 -source 8 一起设置引导类路径的相关解决方案,文中的示例代码讲解详细,有需要的小伙伴可以了解下2025-10-10
如何使用Spring boot的@Transactional进行事务管理
这篇文章介绍了SpringBoot中使用@Transactional注解进行声明式事务管理的详细信息,包括基本用法、核心配置参数、关键注意事项、调试技巧、最佳实践以及完整示例,感兴趣的朋友一起看看吧2025-02-02
MyBatis typeAliases元素标签(含注解方式)及其属性、设置方式
这篇文章主要介绍了MyBatis typeAliases元素标签(含注解方式)及其属性、设置方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2021-09-09
解析Springboot集成Tile38客户端之Set命令实现示例
这篇文章主要为大家介绍了解析Springboot集成Tile38客户端之Set命令实现示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪2022-08-08
eclipse+maven+spring mvc项目基本搭建过程
这篇文章主要介绍了eclipse+maven+spring mvc项目基本搭建过程,本文图文并茂给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下2019-09-09
SpringBoot用ServiceLocatorFactoryBean优雅切换支付渠道
本文主要介绍了SpringBoot用ServiceLocatorFactoryBean优雅切换支付渠道,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2025-10-10


最新评论