嵌套结果性能更好、N+1问题更少,但需手动对齐字段别名;嵌套查询适合复用SQL、逻辑隔离强的场景。

用 <association> 嵌套查询还是嵌套结果?看场景选
直接说结论:嵌套查询(select 属性)适合复用已有 SQL、逻辑隔离强的场景;嵌套结果(resultMap + <id>/<result>)性能更好、N+1 问题更少,但要手动对齐字段别名。
常见错误现象是用了 select 却没写全参数传递,或嵌套结果里漏了 <id> 导致关联对象重复创建(尤其一对多嵌套在多对一里时)。
- 嵌套查询:
<association property="user" column="user_id" select="selectUserById"/>,注意column必须能被外层 SQL 的结果集提供,且selectUserById的参数类型要匹配(如单个int或封装了user_id的对象) - 嵌套结果:
<association property="user" javaType="User"><id property="id" column="user_id"/><result property="name" column="user_name"/></association>,字段别名必须和column一致(比如 SQL 里得写u.id as user_id, u.name as user_name) - 嵌套结果不支持自动映射(
autoMapping默认关闭),哪怕开了,也只映射同名字段,user_name→name这种仍需显式写<result>
<association> 的 fetchType 怎么影响实际执行
默认是 fetchType="eager",只要查主表就立刻触发关联查询;设成 lazy 后,只有首次访问该属性时才查(前提是开启了懒加载,且 session 未关闭)。
容易踩的坑是:设了 lazy 却在 service 层就返回了对象,controller 里再取 user.name 就报 LazyLoadingException —— 因为 session 已关闭。
- 懒加载生效前提:全局配置
lazyLoadingEnabled=true,且aggressiveLazyLoading=false(新版 MyBatis 默认如此) -
fetchType是局部开关,优先级高于全局 eager 配置 - 嵌套查询方式下,
fetchType="lazy"会生成代理对象;嵌套结果方式下,fetchType无效(因为没额外 SQL 可延迟)
多对一和一对一在 <association> 上没区别,但别混淆 <collection>
MyBatis 不区分“多对一”和“一对一”,都用 <association>;真正区分的是数据量:只要目标记录最多一条,就用它。反过来,如果误把一对多写成 <association>,只会取第一条,还不会报错。
典型错误是看到“用户有多个订单”,就想当然在 UserMapper.xml 里用 <association property="orders">,结果永远只拿到一个 Order 对象。
- 一对一/多对一:用
<association property="xxx" javaType="Xxx"> - 一对多/多对多:必须用
<collection property="xxx" ofType="Xxx"> -
javaType和ofType别写反——前者是单个对象类型,后者是集合元素类型
列名冲突时,<association> 的 columnPrefix 怎么用
当主表和关联表都有 id、name 字段,又不想靠别名硬凑,columnPrefix 是最干净的解法。
它不是给 SQL 加前缀,而是告诉 MyBatis:“所有 <association> 里的 column 值,都自动加这个前缀再去找结果集字段”。所以 SQL 里必须提前用别名预留好位置。
- SQL 写法:
SELECT o.id, o.title, u.id as user_id, u.name as user_name FROM order o LEFT JOIN user u ON o.user_id = u.id - XML 写法:
<association property="user" javaType="User" columnPrefix="user_"><id property="id" column="id"/><result property="name" column="name"/></association> -
columnPrefix对嵌套查询方式无效,只作用于嵌套结果 - 别写成
columnPrefix="user."或columnPrefix="user."—— 点号或下划线必须和 SQL 别名严格一致
最常被忽略的是嵌套结果中 <id> 的必要性:它不只是为了主键映射,更是 MyBatis 关联对象去重的依据。漏掉它,一对多嵌套在多对一里时,可能创建多个重复的关联对象实例。










