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 执行计划和链路调用次数三类证据闭环。

相关推荐
可乐ea23 分钟前
【Spring Boot + MyBatis|第4篇】MyBatis 动态 SQL:if、where、foreach 使用详解
java·spring boot·后端·sql·mybatis
vivo互联网技术38 分钟前
动效开发不踩坑:几种动效实现方案对比与实战选型
前端·性能优化·动效
一拳一个娘娘腔44 分钟前
CVE-2026-43284 — Dirty Frag 深度拆解:当零拷贝遇上原地解密,页缓存成了攻击者的画板
linux·缓存
lx188548698961 小时前
Redis大Key阻塞:单线程CPU100%的致命陷阱
数据库·redis·缓存
IT策士1 小时前
Redis 从入门到精通:位图、HyperLogLog、GEO
数据库·redis·缓存
布局呆星1 小时前
Spring Boot + Redis 缓存实战:@Cacheable、序列化踩坑、缓存一致性,一次讲透
spring boot·redis·缓存
elirlove12 小时前
图片页面展示技术实践:从数据管理到性能优化再到安全防护
安全·性能优化
翼龙云_cloud2 小时前
阿里云代理商:部署 DeepSeek V4-Flash解析 快速部署与性能优化
运维·阿里云·性能优化·云计算·ai智能体
努力成为AK大王2 小时前
计算机底层核心原理:CPU、总线、缓存与内存深度解析
缓存·内存·cpu
闪电悠米2 小时前
黑马点评-Redis 消息队列-04_stream_seckill_order
数据库·redis·分布式·缓存·oracle·junit·lua