要让 mybatis 延迟加载生效,必须开启全局配置 lazyloadingenabled=true,同时设置 aggressivelazyloading=false、合理配置 lazyloadtriggermethods,并在 resultmap 的 association/collection 中显式声明 fetchtype="lazy";否则延迟加载不触发。

要让 MyBatis 在真正访问关联对象时才查数据库,关键不是只写 fetchType="lazy",而是必须先打开全局延迟加载开关——lazyLoadingEnabled=true。这个配置是前提,没它,所有 lazy 都不生效。
必须开启的全局配置
在 mybatis-config.xml 的 <settings></settings> 节点里明确设置:
-
<setting name="lazyLoadingEnabled" value="true"></setting>—— 这是总闸门,默认值其实是false(尤其低版本),不能依赖“默认开启” -
<setting name="aggressiveLazyLoading" value="false"></setting>—— 设为false才能实现“按属性触发”,设成true会导致一调 getter 就加载全部关联,失去按需意义 -
<setting name="lazyLoadTriggerMethods" value=""></setting>或留默认(equals,clone,hashCode,toString)—— 建议清空或精简,避免无关方法(比如toString())意外触发加载
映射层必须用 resultMap + fetchType
延迟加载只对 <resultmap></resultmap> 中定义的 <association></association> 或 <collection></collection> 生效,且需显式声明 fetchType="lazy":
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 不能用
resultType直接返回 POJO,那样没有代理注入点 - 不能用
@Select注解写 SQL 并直接返回对象,会绕过 resultMap 解析 - 正确写法示例:
<association property="user" column="uid" select="selectUserById" fetchtype="lazy"></association>
触发时机与常见踩坑点
延迟加载本质是:首次调用代理对象的 getter 方法(如 order.getUser().getName())时,用当前仍存活的 SqlSession 执行预设的 select 语句。
- 如果在 service 层就调用了
getXXX(),而此时 SqlSession 还开着,就会当场触发查询(变成 N+1) - 如果返回给 controller 的对象被 Jackson 序列化,
toString()或遍历集合会强制触发加载 - SqlSession 关闭后再访问 lazy 字段,会抛
ExecutorException: Cannot load lazy result
验证是否生效的小技巧
启动时加日志级别 org.apache.ibatis=DEBUG,观察 SQL 输出:
- 只看到主查询 SQL → 延迟加载已启用
- 后续访问关联属性时才出现第二条 SQL → 触发机制正常
- 主查询后立刻跟出关联 SQL → 检查是否漏配
lazyLoadingEnabled或误用了resultType
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










