MappedStatement
MappedStatement
MappedStatement 是 MyBatis 的核心元数据对象——它把一条 SQL 语句的”所有信息”封装成一个 Java 对象,供执行引擎使用。可以把它理解为:一个 <select>/<insert>/<update>/<delete> 标签(或 @Select 注解)在内存中的等价表示。
一、它”装”了什么
一个 MappedStatement 实例对应 Mapper XML 里的一条 SQL,内部包含:
| 字段 | 含义 |
|---|---|
id |
语句的唯一标识,格式:接口全限定名.方法名,如 com.kewen.UserMapper.selectById |
sqlSource |
真正的 SQL 来源(DynamicSqlSource / RawSqlSource / StaticSqlSource),用来根据参数生成最终 BoundSql |
sqlCommandType |
SELECT / INSERT / UPDATE / DELETE |
parameterMap / parameterType |
入参映射 |
resultMaps |
结果集映射规则(列 → 属性,包括 association、collection 等) |
resultType |
结果类型 |
keyGenerator |
主键生成策略(Jdbc3KeyGenerator / SelectKeyGenerator / NoKeyGenerator) |
keyProperty / keyColumn |
自增主键回填的目标属性/列 |
useCache / flushCacheRequired |
是否使用二级缓存、是否清空缓存 |
cache |
关联的二级缓存对象 |
timeout |
超时时间 |
statementType |
STATEMENT / PREPARED / CALLABLE |
resultSetType |
FORWARD_ONLY / SCROLL_INSENSITIVE 等 |
databaseId |
多数据库厂商支持 |
lang |
脚本语言驱动(默认 XML) |
二、它在 MyBatis 中的位置
1 | Configuration |
**Configuration 是大管家,MappedStatement 是它管理的一条条”SQL 户口”**。Key 就是 id(接口全名 + 方法名),所以 Mapper 接口方法能唯一对应到一条 SQL。
三、它在执行流程中的作用
调用 userMapper.selectById(1) 的过程:
1 | 1. Mapper 代理 (MapperProxy) |
可以看到:整个执行链路(缓存判断、SQL 解析、参数设置、结果映射、主键回填)都从 MappedStatement 里取配置。它就是执行器的”行车手册”。
四、它什么时候被创建
初始化阶段(解析 XML / 注解时),由 MapperBuilderAssistant.addMappedStatement(...) 通过 MappedStatement.Builder 构建:
- XML:
XMLStatementBuilder解析每个<select>/<insert>/...节点 → 生成 MappedStatement - 注解:
MapperAnnotationBuilder解析@Select等注解 → 生成 MappedStatement
构建完毕后注册到 Configuration.mappedStatements,整个生命周期内不可变(只读元数据,所以多线程安全)。
五、一个具象的例子
XML:
1 | <select id="selectById" parameterType="long" resultType="User" useCache="true"> |
启动后变成内存中一个 MappedStatement:
1 | id = "com.kewen.UserMapper.selectById" |
六、和它容易混淆的几个概念
| 对象 | 角色 |
|---|---|
| MappedStatement | 静态元数据:一条 SQL 的所有配置(启动时构建,运行时只读) |
| SqlSource | MappedStatement 的字段,负责把”动态 SQL 模板 + 参数”组装成 BoundSql |
| BoundSql | 运行时产物:最终要执行的 SQL 字符串 + 参数映射列表(每次调用都可能不同) |
| Statement / PreparedStatement | JDBC 层对象,由 StatementHandler 基于 BoundSql 创建 |
简化记忆链:
1 | MappedStatement(静态配置) ──getBoundSql(param)──▶ BoundSql(动态结果) ──▶ PreparedStatement(JDBC执行) |
总结
**MappedStatement = 一条 SQL 的”全量元数据快照”**,是 MyBatis 把 XML/注解配置”对象化”后的产物。它在初始化阶段一次性生成并缓存在 Configuration 里,运行时被 Executor、StatementHandler、ParameterHandler、ResultSetHandler 反复读取,驱动整条 SQL 的执行流程。没有它,MyBatis 就不知道”这条 SQL 怎么解析、怎么传参、怎么映射结果、要不要缓存”。
