Mybatis MappedStatement 封装了哪些信息? 它是如何被创建和使用的?

MappedStatement 是 MyBatis 框架中一个极其核心且重要的对象。我们可以把它理解为一条 SQL 语句(包括 <select>, <insert>, <update>, <delete> 等标签定义的语句)在 MyBatis 内部的完整表示。它封装了执行这条 SQL 所需的所有静态信息

MappedStatement 封装了哪些信息?

MappedStatement 包含的信息非常丰富,几乎涵盖了执行一个数据库操作所需的所有配置细节:

  1. ID (id): 语句的唯一标识符,通常是 namespace + "." + statementId (例如 com.example.mapper.UserMapper.selectUserById)。MyBatis 通过这个 ID 来查找和定位要执行的 SQL 语句。
  2. SQL 源 (SqlSource): 这是最重要的部分之一。它不是简单的 SQL 字符串,而是一个能够根据传入参数动态生成最终可执行 SQL 的对象。
    • 对于静态 SQL(没有 <if>, <foreach> 等动态标签),它可能是 StaticSqlSource
    • 对于包含动态标签的 SQL,它会是 DynamicSqlSource,在运行时解析动态标签并生成最终 SQL。
  3. 命令类型 (SqlCommandType): 标识 SQL 语句的类型,是 SELECT, INSERT, UPDATE, DELETE 中的一种。这决定了 MyBatis 底层会调用 JDBC 的哪种执行方法(executeQuery, executeUpdate)。
  4. 参数类型 (parameterType): 定义了传入该 SQL 语句的参数对象的类型(例如 int, String, java.util.Map, 或某个自定义 Pojo 类)。MyBatis 会根据这个类型处理参数。
  5. 参数映射 (parameterMap/parameterMappings): 定义了如何将传入的 Java 对象属性映射到 SQL 语句中的占位符 (#{}, ${})。parameterMappings 是一个 ParameterMapping 对象的列表,包含了每个参数的属性名、Java 类型、JDBC 类型等信息。
  6. 结果类型 (resultType): 对于 SELECT 语句,定义了期望返回结果的类型(例如 int, String, java.util.Map, 或某个自定义 Pojo 类)。适用于简单结果映射,MyBatis 会尝试自动将列名匹配到对象属性名。
  7. 结果映射 (resultMap/resultMaps): 对于 SELECT 语句,提供了更复杂的、自定义的结果映射规则。ResultMap 对象包含了列名到 Java 对象属性名的详细映射关系、关联查询(association, collection)、鉴别器(discriminator)等高级特性。resultMaps 是一个 ResultMap 对象的列表。
  8. 缓存 (Cache): 关联的二级缓存配置信息。
  9. 刷新缓存 (flushCacheRequired): 指示执行此语句后是否需要清空(刷新)二级缓存(通常 INSERT, UPDATE, DELETE 会设置为 true)。
  10. 使用缓存 (useCache): 指示执行 SELECT 语句时是否尝试从二级缓存中获取结果。
  11. 超时设置 (timeout): SQL 执行的超时时间(单位秒)。
  12. 获取大小 (fetchSize): JDBC 驱动程序每次批量从数据库获取的记录条数。
  13. 语句类型 (statementType): STATEMENT, PREPARED, CALLABLE 中的一种,指示 MyBatis 使用 JDBC 的哪种 Statement 类型执行 SQL(默认为 PREPARED,即 PreparedStatement)。
  14. 结果集类型 (resultSetType): FORWARD_ONLY, SCROLL_SENSITIVE, SCROLL_INSENSITIVE 中的一种,控制 JDBC ResultSet 的类型。
  15. 数据库厂商 ID (databaseId): 用于支持多数据库厂商的 SQL 语句。
  16. 语言驱动 (lang): 用于解析 SQL 语句的语言驱动,允许扩展(默认是处理 XML 标签的驱动)。
  17. 主键生成策略 (keyGenerator, keyProperties, keyColumn): 用于处理 INSERT 语句后获取自动生成的主键。

MappedStatement 是如何被创建的?

MappedStatement 的创建发生在 MyBatis 初始化阶段,当 MyBatis 解析配置文件(mybatis-config.xml)和 Mapper 文件(XML 或注解)时:

  1. 解析入口: MyBatis 的 Configuration 对象负责管理所有的配置信息。在构建 SqlSessionFactory 的过程中,会触发对 Mapper 文件(通过 <mappers> 标签或 mapper-locations 指定)或 Mapper 接口注解的解析。
  2. XML 解析: 对于 XML Mapper 文件,XMLMapperBuilder 会负责解析文件内容。当遇到 <select>, <insert>, <update>, <delete> 等 SQL 语句标签时,会调用 XMLStatementBuilder
  3. 注解解析: 对于使用注解的 Mapper 接口,MapperAnnotationBuilder 会解析接口及其方法上的 @Select, @Insert 等注解。
  4. 信息提取: 无论是 XMLStatementBuilder 还是 MapperAnnotationBuilder,它们都会从 XML 标签的属性或注解中提取上面列出的各种配置信息(ID、parameterType、resultType、SQL 内容等)。
  5. 创建 SqlSource: 根据 SQL 内容是否包含动态标签,创建相应的 SqlSource 对象(StaticSqlSourceDynamicSqlSource)。
  6. 构建 MappedStatement: 使用 MappedStatement.Builder 模式,将提取到的所有信息(包括创建好的 SqlSource)设置到 Builder 中,最后调用 build() 方法创建一个不可变 (Immutable)MappedStatement 对象。
  7. 注册到 Configuration: 创建好的 MappedStatement 对象会被添加到 Configuration 对象的一个 MapmappedStatements)中,以其唯一的 ID 作为 Key 进行存储。

这个创建过程在应用程序启动时完成一次,之后 MappedStatement 对象就会常驻内存,供后续运行时使用。

MappedStatement 是如何被使用的?

MappedStatement运行时被用来执行实际的数据库操作:

  1. Mapper 接口调用: 当你调用一个 Mapper 接口的方法时(例如 userMapper.selectUserById(1)),MyBatis 的代理机制会拦截这个调用。
  2. 定位 MappedStatement: MyBatis 根据调用的接口方法名(结合接口的命名空间)生成 MappedStatement 的 ID,然后从 ConfigurationmappedStatements Map 中查找并获取对应的 MappedStatement 对象。
  3. 获取 SqlSession 和 Executor: 调用通常发生在 SqlSession 的上下文中。SqlSession 会获取一个 Executor(执行器,如 SimpleExecutor, ReuseExecutor, BatchExecutor)。
  4. 参数处理和 SQL 生成: Executor 会使用 MappedStatement 中的 SqlSource 和传入的参数对象,调用 SqlSource.getBoundSql(parameterObject) 方法。这一步会处理动态 SQL 标签,生成最终的可执行 SQL 字符串以及对应的参数映射信息,封装在 BoundSql 对象中。BoundSql 包含了本次执行的具体 SQL 和参数值。
  5. 语句执行: Executor 根据 MappedStatement 中的 SqlCommandTypestatementType,使用 JDBC 连接和 BoundSql 中的信息,创建 PreparedStatement(或其他类型 Statement),设置参数,并执行 SQL 语句(调用 executeQueryexecuteUpdate)。
  6. 结果处理 (对 SELECT): 如果是 SELECT 语句,Executor 会获取 ResultSet。然后,ResultSetHandler 会利用 MappedStatement 中定义的 resultMapresultType 信息,将 ResultSet 中的数据映射成 Java 对象(或列表、Map)。
  7. 缓存处理: 在执行前后,Executor 会根据 MappedStatement 的缓存配置进行二级缓存的读写或刷新操作。
  8. 返回结果: 最终的处理结果(查询到的对象、影响的行数等)被返回给调用者(Mapper 接口的调用处)。

总结:

MappedStatement 是 MyBatis 中定义和存储单个 SQL 操作所有静态配置信息的蓝图模板。它在 MyBatis 初始化时被解析和创建,并存储在全局的 Configuration 中。在运行时,MyBatis 根据方法调用找到对应的 MappedStatement,并结合传入的参数动态生成 SQL (BoundSql),然后利用 MappedStatement 中的配置信息(如结果映射、缓存策略等)来执行数据库操作和处理结果。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰糖心书房

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值