MyBatis懒加载的核心目标是按需加载关联数据,即“用到才查,不用不查”;需全局配置lazyLoadingEnabled=true和aggressiveLazyLoading=false,并在association或collection中显式设置fetchType="lazy"。

MyBatis 懒加载的核心目标是避免一次性加载大量关联数据,从而减少内存占用和数据库压力。它不是“关掉关联查询”,而是让关联数据在真正被访问时才查——用到才查,不用不查。
全局开关必须打开
懒加载默认是关闭的,必须在 mybatis-config.xml 的 <settings> 中显式启用:
- lazyLoadingEnabled = true:开启懒加载总开关,没有这一步,所有局部配置都无效
-
aggressiveLazyLoading = false:关键!设为
false才能实现“按属性触发”,即只加载你调用的那个 getter 对应的关联数据;若设为true,只要调用对象任意方法(比如toString()或equals()),就会把所有懒加载字段全查出来,失去懒加载意义 - 可选配置
proxyFactory="CGLIB":推荐保留默认,CGLIB 代理对 final 类兼容性更好
映射文件中明确指定懒加载行为
仅开全局开关还不够,还需在 <association>(一对一)或 <collection>(一对多)标签中声明懒加载策略:
- 使用 fetchType="lazy":这是最直接、推荐的方式。例如:
<association property="user" column="user_id" select="selectUserById" fetchType="lazy"/> - 不建议依赖
lazy="true"属性(旧版写法),因部分 MyBatis 版本已弃用或行为不稳定 - 确保
select引用的语句存在且参数匹配,否则运行时报NullPointerException或空集合
注意 N+1 查询的实际影响
懒加载虽省内存,但会把“1次 JOIN 查询”拆成“1次主查 + N 次子查”。如果批量操作中频繁访问关联属性(如循环调用 order.getUser().getName()),可能引发大量单条 SQL,拖慢整体响应。
立即学习“Java免费学习笔记(深入)”;
- 解决思路:对已知要批量使用的场景,改用 立即加载(fetchType="eager")或 分步查询 + 手动组装
- 开发阶段可用 MyBatis Log Plugin 或日志级别设为 DEBUG,观察是否出现意料外的重复子查询
- 线上环境建议配合监控,识别高频触发懒加载的接口并评估优化必要性
实体类与 getter 方法不能破坏代理机制
MyBatis 通过 CGLIB 或 Javassist 创建代理对象,以下写法会导致懒加载失效或抛异常:
- 实体类声明为 final:CGLIB 无法继承,代理创建失败
- 关联属性的 getter 方法被 private / final / static 修饰:代理无法拦截调用
- 在构造函数、
init方法或 JSON 序列化(如 FastJSON 默认调用所有 getter)中提前访问懒加载属性:等于主动触发,失去延迟意义


















