跳到正文
Elaine Blog
返回

MyBatis SQL 执行、缓存与结果映射

MyBatis、MySQL 与数据架构

一次 Mapper 方法调用最终仍是 JDBC:准备 SQL、绑定参数、发送给数据库、读取结果。MyBatis 的价值是把这些重复步骤组成稳定管线,而不是绕过 JDBC。

Table of contents

Open Table of contents

一次查询的主线

MapperProxy
  → MappedStatement
  → Executor
  → StatementHandler
  → ParameterHandler
  → JDBC PreparedStatement
  → ResultSetHandler
  → Java 对象

Executor 负责缓存、事务相关协调和执行策略;StatementHandler 创建并执行 JDBC Statement;ParameterHandler 把 Java 参数绑定到 ?ResultSetHandler 把结果集转换为对象。

OrderMapper.java下载开启了下划线转驼峰映射,所以 user_id 能进入 userId。生产查询建议明确列名,不写 SELECT *,这样 Schema 变化不会悄悄改变映射和网络负载。

一级缓存为什么只执行一次 SQL

运行:

mvn -Dtest=DataArchitectureLabTest#firstLevelCacheAvoidsSecondStatementPreparation test

同一个 SqlSession 用相同语句、参数和分页条件查询两次,第二次命中本地缓存。一级缓存默认作用域是会话;执行更新、提交、回滚或关闭会话会清理相关缓存。它不能替代 Redis,也不能让多个请求共享数据。

二级缓存以 Mapper 命名空间为边界,可跨会话,但一致性、序列化和失效更复杂。除非已证明数据库读取是瓶颈并设计好失效策略,否则先不用它。

结果映射的两种方式

简单表可以自动映射。关联对象、一对多集合或不同命名需要 resultMap 明确声明。嵌套查询容易产生 N+1:查 100 个订单后,再为每个订单查一次用户,总计 101 条 SQL。嵌套结果则用一次 Join 返回扁平行,再组装对象,但要注意重复数据量。

排查顺序

遇到“字段为 null”时,依次检查 SQL 列名、别名、Java 属性名、构造器、TypeHandler 和自动映射设置;遇到“SQL 次数过多”,先记录语句 ID、耗时和调用次数,再判断是缓存未命中还是 N+1。

下一步

继续阅读06-03 MyBatis 插件、批处理与性能陷阱,用插件观察 SQL,并把批处理的提交语义说清楚。


分享这篇文章:

上一篇
MyBatis 配置解析与核心对象
下一篇
MyBatis 插件、批处理与性能陷阱