Mybatis源码分析——MappedStatement(2)

上一篇主要讲了MappedStatement基本概念,接下来主要分析动态sql语句怎么解析成MappedStatement。

在 MyBatis 中,动态 SQL 是指根据条件动态生成 SQL 语句的功能。动态 SQL 语句通常在 Mapper 文件中使用 <if>, <choose>, <when>, <otherwise>, <foreach> 等标签来实现。当 MyBatis 执行动态 SQL 时,它会将这些动态 SQL 解析成一个 MappedStatement 对象,然后通过 Executor 执行相应的 SQL。

1. 动态 SQL 的解析过程

动态 SQL 的解析主要是通过 SQL 构建器和动态 SQL 标签(如 <if>, <choose>, <when>, <foreach> 等)来实现的。MyBatis 在解析这些动态标签时,会生成相应的 SQL 语句,并将其包装成 MappedStatement 对象。

1.1. 动态 SQL 标签

在 MyBatis 的 XML 配置文件中,动态 SQL 是通过一组特定的标签来实现的。例如:

<select id="selectUsers" resultType="User">
    SELECT * FROM users
    <where>
        <if test="name != null">AND name = #{name}</if>
        <if test="age != null">AND age = #{age}</if>
    </where>
</select>

在上面的例子中,<if> 标签根据传入的条件来动态生成 SQL 语句。如果 name 不为空,则会生成 AND name = #{name} 部分;如果 age 不为空,则会生成 AND age = #{age} 部分。<where> 标签会根据是否有动态条件生成 WHERE 子句。

1.2. 动态 SQL 解析的关键组件

在 MyBatis 中,动态 SQL 的解析过程通常涉及以下几个步骤:

  1. SQL 源 (SqlSource) 的生成

    • 在解析动态 SQL 时,MyBatis 会根据 Mapper 文件中的 XML 标签生成一个 SqlSource 对象。SqlSource 对象负责保存原始的 SQL 语句及其动态部分。它包含了 SQL 的模板(即静态部分)和动态 SQL 条件(即根据输入条件决定是否加入的部分)。
  2. DynamicSqlSource

    • DynamicSqlSource 是 MyBatis 中处理动态 SQL 的类,它会将动态部分和静态部分结合起来,动态构建最终的 SQL 语句。
    • 在执行 SQL 时,DynamicSqlSource 会根据输入参数的不同,动态地生成最终的 SQL 语句。
  3. 生成 MappedStatement

    • Mapper 文件解析的过程中,MyBatis 会根据 id、SQL 类型、参数类型、返回类型等生成一个 MappedStatement。这个 MappedStatement 对象会包含对应的 SqlSource,它负责执行 SQL 查询时生成最终的 SQL 语句。

2. 动态 SQL 解析流程

以下是 MyBatis 解析动态 SQL 并生成 MappedStatement 的主要步骤:

2.1. 解析 Mapper 文件

当 MyBatis 启动时,SqlSessionFactory 会解析 Mapper 文件中的 SQL 映射语句(<select><insert><update><delete>)。在解析过程中,如果遇到动态 SQL 标签(如 <if><choose><foreach> 等),MyBatis 会调用相应的解析器来处理这些标签。

2.2. 生成 SqlSource

对于动态 SQL,MyBatis 会为每个动态 SQL 语句生成一个 SqlSource 对象。SqlSource 是 MyBatis 用来构建 SQL 的接口,它的实现类有:

  • StaticSqlSource:用于普通静态 SQL。
  • DynamicSqlSource:用于动态 SQL。

DynamicSqlSource 会在 SQL 执行时根据参数动态地生成最终的 SQL 语句。SqlSource 对象不仅包含了 SQL 的文本模板,还包含了如何根据输入参数动态生成 SQL 的逻辑。

2.3. 构建 MappedStatement

MappedStatement 是 MyBatis 中一个非常核心的类,它封装了与 SQL 执行相关的所有元数据(如 SQL、返回值类型、参数类型等)。MyBatis 会根据映射文件中的配置,构建一个 MappedStatement 对象。

以下是 MappedStatement 的构建过程:

MappedStatement.Builder builder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType);
builder.parameterMap(parameterMap);
builder.resultMaps(resultMaps);
MappedStatement mappedStatement = builder.build();
  • id:表示该映射语句的唯一标识符,通常是 SQL 语句的 id 属性。
  • sqlSource:表示 SQL 源,这里会传入动态 SQL 的 SqlSource
  • sqlCommandType:SQL 执行类型,如 SELECTINSERTUPDATEDELETE
  • parameterMap:表示 SQL 语句的参数映射,描述如何将输入参数传递到 SQL 语句中。
  • resultMaps:表示 SQL 查询结果的映射,描述如何将查询结果转换为 Java 对象。
2.4. MappedStatement 注册到 Configuration

MyBatis 在解析所有 Mapper 文件时,会将生成的 MappedStatement 对象存储在 ConfigurationmappedStatements 中,使用 SQL 语句的 id 作为键。这些 MappedStatement 对象将在 SQL 执行时被 Executor 用来执行具体的 SQL 操作。

2.5. 执行 SQL

Executor 执行 SQL 时,MappedStatement 会被检索到,并且通过 SqlSource 动态生成最终的 SQL 语句。Executor 根据生成的 SQL 执行查询、插入、更新等操作。

3. 动态 SQL 的实现机制

MyBatis 使用了 OGNL(Object-Graph Navigation Language)表达式语言来处理动态 SQL 标签中的条件判断。这使得 MyBatis 可以在 XML 文件中通过 OGNL 表达式来控制 SQL 语句的生成。

例如,在 <if> 标签中:

<if test="name != null">AND name = #{name}</if>

MyBatis 会解析 test="name != null" 中的 OGNL 表达式,判断 name 是否为 null,如果不为 null,则将 AND name = #{name} 这部分 SQL 添加到最终的 SQL 中。

4. SqlSource 的解析

SqlSource 是 MyBatis 动态 SQL 的核心接口,MyBatis 提供了两种实现类:

  • StaticSqlSource:用于静态 SQL 查询,它只是将 SQL 作为字符串保存。
  • DynamicSqlSource:用于动态 SQL 查询,负责根据参数动态生成 SQL。

DynamicSqlSource 是 MyBatis 处理动态 SQL 的关键类,它会解析动态 SQL 标签并根据实际的条件构建最终的 SQL。

动态 SQL 示例:DynamicSqlSource 处理过程

假设你有以下的动态 SQL 语句:

<select id="selectUser" resultType="User">
    SELECT * FROM user
    <where>
        <if test="name != null">AND name = #{name}</if>
        <if test="age != null">AND age = #{age}</if>
    </where>
</select>
  1. DynamicSqlSource 创建:在解析过程中,MyBatis 会根据这个 SQL 语句创建一个 DynamicSqlSource 对象。
  2. SqlNode 解析DynamicSqlSource 会将 XML 中的 SQL 语句分解成多个 SqlNode,例如 <where><if> 标签会分别转换成 WhereSqlNodeIfSqlNode
  3. SQL 拼接:当调用 SQL 时,DynamicSqlSource 会检查输入的参数,执行 OGNL 表达式,决定是否将每个动态部分(如 AND name = #{name})添加到最终的 SQL 语句中。

5. 总结

  • 动态 SQL 是 MyBatis 中根据条件动态生成 SQL 语句的功能,通常通过 <if><choose><foreach> 等标签来实现。
  • MyBatis 通过 SqlSource 来构建 SQL,DynamicSqlSource 会根据动态标签生成最终的 SQL 语句。
  • MappedStatement 是 MyBatis 中封装 SQL 语句、参数类型、返回类型等元数据的对象,它包含了动态 SQL 语句的生成逻辑和执行信息。
  • 解析后的 MappedStatement 会被 Executor 执行,最终根据不同的输入参数动态生成并执行 SQL。

动态 SQL 的解析过程是 MyBatis 强大功能的核心之一,通过灵活的 XML 标签和 OGNL 表达式,MyBatis 能够根据不同的业务需求生成灵活的 SQL 查询。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值