查不出子集合主因是resultmap嵌套结构未配对或sql未用join返回子项字段;property名须与java字段完全一致;sql需显式列子表字段并用别名;join分页易错乱,应先查主表id再关联。

为什么 <collection></collection> 总是查不出子集合?
多数时候不是写法错,而是没配对 resultMap 的嵌套结构或忽略了 SQL 的 JOIN 方式。MyBatis 不会自动“拼装”一对多关系,它只按你写的映射规则把结果集字段塞进对象——如果 SQL 没返回子项字段,或者 <collection></collection> 的 property 和 Java 字段名不一致,集合就为空。
-
<collection></collection>的property必须和父类中 List 类型字段名完全一致(区分大小写),比如private List<orderitem> items;</orderitem>就得写property="items" - SQL 里别用
SELECT *,必须显式列出所有子表字段,并用别名避免列名冲突,例如item.id as "items.id" - 若用
JOIN查一对多,结果集必然是笛卡尔积,MyBatis 靠id字段(通常是主键)做分组聚合,所以<id></id>标签不能漏,且要覆盖父级和子级的唯一标识字段
嵌套结果映射(resultMap 套 resultMap)怎么写才不崩?
这是最常用也最容易翻车的方式:外层 resultMap 描述主对象,内层用 <collection></collection> 引用另一个 resultMap 描述子对象。关键在“引用路径”和“字段归属”。
- 子
resultMap的id必须唯一,且最好带命名空间前缀,比如com.example.OrderMapper.ItemResultMap,避免全局冲突 -
<collection></collection>的ofType要写子对象的完整类名(或已定义的别名),比如ofType="OrderItem",不能写ofType="list"或留空 - 子
resultMap里的<id></id>和<result></result>字段名,要和 SQL 返回的列名(或别名)严格对应,MyBatis 不做驼峰转换——除非你开了mapUnderscoreToCamelCase=true
<resultmap id="OrderResultMap" type="Order"><id property="id" column="order_id"></id><result property="name" column="order_name"></result><collection property="items" oftype="OrderItem" resultmap="ItemResultMap"></collection></resultmap><p><resultmap id="ItemResultMap" type="OrderItem"><id property="id" column="item_id"></id><result property="sku" column="item_sku"></result></resultmap></p>
<collection></collection> 用 select 属性时为啥 N+1 查询没生效?
用 select 属性走“延迟加载 + 单条查询”路径,看似优雅,但默认不开启延迟加载,而且容易因缓存、事务或参数传递问题直接失效。
- 必须在 MyBatis 配置里打开
lazyLoadingEnabled=true,否则select形式退化为立即执行,还可能报NullPointerException -
<collection></collection>的select值是另一个statement的 ID,比如select="selectItemsByOrderId",它对应的 SQL 必须接受一个参数(通常是父对象的 ID 字段),且参数名要和column指定的列名一致 - 如果父查询用了
resultType而非resultMap,<collection></collection>的select会被忽略——MyBatis 只在resultMap下识别关联配置
MySQL 分页 + 一对多时 <collection></collection> 数据错乱怎么办?
用 LIMIT 直接套在 JOIN 查询上,会导致分页数不准、子项重复或丢失——因为分页发生在 JOIN 后的宽表上,不是按主表逻辑切片。
- 不要在含
<collection></collection>的 SQL 里直接写LIMIT,先查主表 ID 列表(带分页),再用select属性批量查子项,或改用嵌套结果映射 +rowBounds(但仅限无 JOIN 场景) - 若坚持用 JOIN 分页,需用子查询先取主表分页结果,再和子表关联,例如:
SELECT * FROM order o JOIN (SELECT id FROM order ORDER BY id LIMIT 10) page ON o.id = page.id JOIN order_item i ON o.id = i.order_id - 注意驱动版本兼容性:MySQL 8.0+ 对派生表别名要求更严,
page这种别名必须存在,否则报Every derived table must have its own alias
嵌套映射真正难的不是语法,是理解 MyBatis 如何把扁平的结果集还原成树形结构——它靠的是字段名匹配、ID 分组、以及你有没有让每一条记录都携带足够的上下文信息。少一个 <id></id>,或多一个没处理的 NULL 字段,整个集合就塌了。










