MyBatis 性能优化:批处理、分页、缓存与慢 SQL 定位

目标:你能把 MyBatis 的性能问题拆成"SQL 本身 + JDBC/网络 + MyBatis 使用方式"三层,并掌握可落地的优化点。

1. 性能问题先分层:不要一上来就调 MyBatis

MyBatis 慢,常见根因优先级通常是:

  1. SQL/索引设计(占大头)
  2. 连接池/网络/DB 负载
  3. MyBatis 使用方式(N+1、错误分页、批处理不当)

面试时你要体现"先定位再优化"的工程能力。

2. N+1 问题:最常见的 ORM 性能坑

典型场景:

  • 查主表 N 条,再对每条查一次明细表
  • 日志里表现为一堆重复 SQL

解决方案:

  • 一次性 join 或 IN 批量查询
  • resultMap 做聚合映射(注意去重)
  • 业务层做批量预取

排查手段:

  • 打开 SQL 日志,观察是否出现"同模板 SQL 重复执行 N 次"
  • 用链路追踪看 DB span 数量是否异常

3. 分页:你以为用了分页,其实在内存分页

3.1 正确分页:让 DB 做 limit/offset 或基于游标

  • limit offset, size 简单但 offset 大时会慢
  • 大翻页建议:
    • 基于主键/索引的"seek"方式(where id > lastId limit size)

3.2 常见坑:不小心触发全量查询

  • 没有加 limit
  • PageHelper/拦截器没生效(配置顺序、插件冲突)

排查:

  • 看最终发到 DB 的 SQL 是否有 limit

4. 批处理:减少网络往返,但别把内存打爆

4.1 批处理的收益

  • 单条插入 1000 次 = 1000 次网络往返
  • 批处理 = 1 次或少量往返

4.2 常见误区

  • 一次攒太大批次:
    • MyBatis/JDBC 会缓存参数,容易占用大量内存
  • 没有控制事务:
    • 批处理通常应显式事务,否则每条 auto-commit 性能差

建议:

  • 分批提交(例如 500/1000 一批)
  • 明确事务边界
  • 监控单次批处理耗时与失败重试策略

5. 缓存:一级缓存别神化,二级缓存要谨慎

5.1 一级缓存(SqlSession 级别)

  • 同一个 SqlSession 内重复查询可命中
  • 默认开启

坑:

  • 与事务/会话生命周期强相关
  • 在 Web 应用中通常每次请求一个 SqlSession,收益有限

5.2 二级缓存(Mapper 级别)

  • 跨 SqlSession
  • 需要显式开启,且对象要可序列化

风险:

  • 一致性:更新后缓存失效策略复杂
  • 命中率:命中低反而多一次序列化开销

建议:

  • 更推荐把缓存放到 Redis/本地缓存层,用更可控的失效策略
  • 二级缓存只用于少量稳定读、低写场景

6. 慢 SQL 定位:从 MyBatis 到数据库的闭环

6.1 你需要的三类证据

  • 应用侧:SQL 模板、参数、耗时、调用栈
  • DB 侧:慢日志、执行计划、锁等待
  • 链路侧:某接口中 DB 调用次数与分布

6.2 常见慢因

  • 索引失效(隐式类型转换、函数包裹列、like 前缀 %
  • 返回列过多(select *)
  • 大 offset 分页
  • 锁等待(更新热点行)

6.3 MyBatis 相关的定位点

  • 是否存在大量小 SQL(N+1)
  • 是否事务过大导致锁持有时间长
  • 是否执行了不必要的 flush

7. 参数与映射:性能与正确性的隐形成本

  • 大字段(TEXT/BLOB)不要随意查出来
  • 合理使用延迟加载(谨慎:容易触发 N+1)
  • resultMap 的嵌套映射要注意去重与集合膨胀

8. 面试背诵稿(45 秒)

MyBatis 性能优化我会先分层:优先看 SQL 和索引,再看连接池与 DB 负载,最后才是 MyBatis 使用方式。

最常见的问题是 N+1,我会用 join 或 IN 批量预取解决;分页要确保最终 SQL 带 limit,并且大翻页用基于索引的 seek 分页。

批处理能显著减少网络往返,但要控制批次大小并明确事务边界避免内存膨胀。

缓存方面一级缓存作用受 SqlSession 生命周期限制,二级缓存一致性成本高,通常更建议用独立缓存层。

定位慢 SQL 时要把应用侧 SQL+参数、DB 执行计划和链路调用次数三类证据闭环。

相关推荐
apocelipes5 小时前
常用编程语言和库的正则表达式性能对比
c语言·c++·python·性能优化·golang·开发工具和环境
考虑考虑2 天前
Mybatis实现批量插入
java·后端·mybatis
你听得到114 天前
用户说 App 卡,但说不清在哪?我把 Flutter 监控 SDK 升级成了链路观测工作台
前端·flutter·性能优化
亲亲小宝宝鸭7 天前
前端性能监控:web-vitals
前端·性能优化·监控
小七-七牛开发者8 天前
TokenPilot:让 LLM Agent 长会话成本降 60%+ 的上下文管理
缓存·agent·token·context·上下文·推理成本
TrisighT11 天前
Electron 跑在鸿蒙 PC 上,单窗口和多窗口内存差 800MB?我抓了 5 组数据
性能优化·electron·harmonyos
jump_jump14 天前
流式 HTML:从 htmx 片段装配到浏览器原生增量渲染
javascript·性能优化·前端工程化
小小工匠15 天前
Redis - 事务机制:能实现 ACID 属性吗
数据结构·redis·性能优化·并发·持久化
ofoxcoding15 天前
在AI API聚合平台配置DeepSeek V3.2提示词缓存实战:快速接入与成本优化指南
人工智能·spring·缓存·ai