最直接有效的办法是用 JOIN 配合 resultMap 一次性查出全部数据,替代嵌套 select;SQL 中显式 LEFT JOIN 并加字段别名,resultMap 精简映射、明确 ofType 和 <id>,慎用延迟加载并配批量机制,读多写少数据启用二级缓存。

最直接有效的办法是用 JOIN 配合 resultMap 一次性查出全部数据,而不是让 MyBatis 对每条主记录再发一次子查询。
用 JOIN 替代嵌套 select
别在 <collection> 里写 select="xxx"。改成在 SQL 中显式 LEFT JOIN,并给字段加别名避免冲突:
- 主表字段(如
u.id,u.name)直接映射到主对象属性 - 关联表字段(如
o.id as order_id,o.amount)必须加别名,防止列名重复 -
<collection>内用<id>和<result>明确指定子对象字段,MyBatis 会按主键自动分组组装
精简 resultMap 和 SQL 字段
每个映射字段都会参与解析,冗余字段拖慢性能、浪费内存:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- SQL 中只
SELECT实际需要的列,禁用SELECT * - resultMap 里只保留业务真正用到的
<id>和<result>,删掉废弃或注释掉的项 - 集合映射中明确声明
ofType和唯一标识<id>,帮助 MyBatis 正确去重和分组
慎用延迟加载,必须配批量机制
单独开 lazyLoadingEnabled 只是把“立即 N+1”变成“访问时 N+1”,不解决问题:
立即学习“Java免费学习笔记(深入)”;
- 全局启用:
<setting name="lazyLoadingEnabled" value="true"/> - 关闭激进模式:
<setting name="aggressiveLazyLoading" value="false"/> - 在
<collection>中显式写fetchType="lazy",且确保 SqlSession 未提前关闭 - 关键:搭配批量加载逻辑(如自定义拦截器或二次查询优化),否则仍可能触发 N 次单条查询
对读多写少数据启用二级缓存
适合省市区、字典项、状态码等变动不频繁的关联数据:
- 在 Mapper XML 顶部加
<cache /> - 配置淘汰策略(如
eviction="LRU")和刷新周期(如flushInterval="60000") - 注意:缓存的是整个查询结果,不是单个子对象;主表更新时需同步清除对应缓存


















