上一篇主要讲了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 的解析过程通常涉及以下几个步骤:
-
SQL 源 (
SqlSource
) 的生成:- 在解析动态 SQL 时,MyBatis 会根据
Mapper
文件中的 XML 标签生成一个SqlSource
对象。SqlSource
对象负责保存原始的 SQL 语句及其动态部分。它包含了 SQL 的模板(即静态部分)和动态 SQL 条件(即根据输入条件决定是否加入的部分)。
- 在解析动态 SQL 时,MyBatis 会根据
-
DynamicSqlSource
:DynamicSqlSource
是 MyBatis 中处理动态 SQL 的类,它会将动态部分和静态部分结合起来,动态构建最终的 SQL 语句。- 在执行 SQL 时,
DynamicSqlSource
会根据输入参数的不同,动态地生成最终的 SQL 语句。
-
生成
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 执行类型,如SELECT
、INSERT
、UPDATE
、DELETE
。parameterMap
:表示 SQL 语句的参数映射,描述如何将输入参数传递到 SQL 语句中。resultMaps
:表示 SQL 查询结果的映射,描述如何将查询结果转换为 Java 对象。
2.4. MappedStatement
注册到 Configuration
中
MyBatis 在解析所有 Mapper
文件时,会将生成的 MappedStatement
对象存储在 Configuration
的 mappedStatements
中,使用 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>
DynamicSqlSource
创建:在解析过程中,MyBatis 会根据这个 SQL 语句创建一个DynamicSqlSource
对象。SqlNode
解析:DynamicSqlSource
会将 XML 中的 SQL 语句分解成多个SqlNode
,例如<where>
和<if>
标签会分别转换成WhereSqlNode
和IfSqlNode
。- 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 查询。