0.引入
动态 SQL 是指在程序执行过程中,根据实际的情况动态构建 SQL 语句。
在 MyBatis 中,动态 SQL 是用一些标签(如 <if>
、<choose>
、<where>
、<set>
等)来实现的。这些标签可以根据传入的参数动态地添加、删除或修改 SQL 语句的某些部分。
1. 为什么需要动态 SQL
在开发中,往往会遇到以下情况:
- 条件不确定:根据不同的条件,查询的字段、排序规则或者筛选条件可能会有所不同。
- 查询复杂性:某些查询可能包含多个可选条件,如果每种组合都写一个 SQL 语句,代码会变得非常冗长。
- 可扩展性:有时系统需求会发生变化,新的查询条件和筛选项可能会不断增加,使用静态 SQL 会使得代码的扩展变得困难。
2. MyBatis 中的动态 SQL
在 MyBatis 中,动态 SQL 是通过 XML 配置 文件中使用特定的标签来完成的。常见的标签有:
<if>
:如果条件为真,则包括该 SQL 片段。<choose>
:用于多条件的选择,相当于if-else
。<when>
:用于在<choose>
中定义条件。<otherwise>
:用于在<choose>
中定义默认条件。<where>
:用于自动处理 SQL 语句中的WHERE
子句,去掉多余的AND
。<set>
:用于更新操作的 SQL,自动处理SET
语句中的字段。<foreach>
:用于遍历集合,动态生成 SQL 中的多个元素。
3. 常见的动态 SQL 示例
3.1 <if>
:条件判断
<if>
标签根据传入的条件判断是否包含该 SQL 片段。常用于 WHERE
子句中的条件判断。
<select id="findUserByCondition" resultType="User">
SELECT * FROM users
<where>
<if test="username != null">AND username = #{username}</if>
<if test="age != null">AND age = #{age}</if>
</where>
</select>
在上面的例子中,<if>
标签用来判断 username
和 age
是否为 null
,如果不为 null
,则将相应的条件添加到 SQL 查询中。
3.2 <choose>、<when>、<otherwise>
<choose>
标签类似于 Java 中的 if-else
语句(或者说switch
语句),用于 选择 一条匹配的语句执行的标签,它包含多个 <when>
条件语句和一个 <otherwise>
默认条件。
<when>
用于指定条件,它会根据test
属性中的表达式进行判断。如果条件为true
,则执行对应的 SQL 片段。<otherwise>
用于提供一个 默认条件,当所有<when>
中的条件都不满足时,<otherwise>
会被执行。
<select id="findUserByType" resultType="User">
SELECT * FROM users
<where>
<choose>
<when test="userType == 'admin'">
role = 'admin'
</when>
<when test="userType == 'guest'">
role = 'guest'
</when>
<otherwise>
role = 'user'
</otherwise>
</choose>
</where>
</select>
在这个例子中,<choose>
根据 userType
的值决定查询 role
的条件。若 userType
为 admin
,查询条件为 role = 'admin'
;若 userType
为 guest
,则查询条件为 role = 'guest'
;否则,查询条件为 role = 'user'
。
3.3 <where>
:自动添加 WHERE
子句
<where>
标签用于自动处理 SQL 语句中的 WHERE
子句。它会自动去除整个子句前面多余的 AND
或 OR
。
<select id="findUserByCondition" resultType="User">
SELECT * FROM users
<where>
<if test="username != null">AND username = #{username}</if>
<if test="age != null">AND age = #{age}</if>
</where>
</select>
使用 <where>
时,MyBatis 会自动将第一个条件前加上 WHERE
,之后的条件会自动处理为 AND
,且多余的 AND
会被去除。
和 where 元素等价的自定义 trim 元素为:
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
3.4 <set>
:处理更新 SQL 中的 SET
语句
<set>
标签用于生成 UPDATE
语句的 SET
部分,它会自动去除多余的 AND
。
<update id="updateUser">
UPDATE users
<set>
<if test="username != null">username = #{username},</if>
<if test="email != null">email = #{email},</if>
<if test="age != null">age = #{age},</if>
</set>
WHERE id = #{id}
</update>
在上面的例子中,<set>
标签用来处理 UPDATE
语句中的动态字段。如果某个字段为 null
,就不会出现在 SET
部分,避免了多余的逗号和条件。
和 set 元素等价的自定义 trim 元素为:
<trim prefix="SET" suffixOverrides=",">
...
</trim>
3.5 <foreach>
:遍历集合或数组
<foreach>
用于在 SQL 语句中循环处理集合或数组,常用于 IN
子句等。
<select id="findUsersByIds" resultType="User">
SELECT * FROM users
WHERE id IN
<foreach item="id" collection="ids" open="(" separator="," close=")">
#{id}
</foreach>
</select>
在这个例子中,<foreach>
会将 ids
集合中的每个元素生成一个 IN
子句中的值,并且自动加上括号和逗号分隔符。
详细可见:【MyBatis】<foreach> 详解
4. 动态 SQL 的优缺点
优点:
- 灵活性高:可以根据不同的参数和条件,动态构建查询或更新语句。
- 代码简洁:避免了冗长的多个
if
判断和 SQL 语句,可以通过一个动态 SQL 语句实现复杂的查询逻辑。 - 减少重复:通过动态 SQL,避免了为每种查询条件都编写单独的 SQL 方法。
缺点:
- 调试困难:动态 SQL 由于是根据条件动态生成的,可能导致生成的 SQL 难以调试和查看,特别是在日志中。
- 性能问题:过度使用动态 SQL,可能会导致 SQL 语句变得过于复杂,影响数据库执行效率。
5. 总结
- 动态 SQL 是 MyBatis 强大的功能之一,它通过各种标签如
<if>
、<choose>
、<foreach>
等灵活地插入或删除查询条件。 - 动态 SQL 适用于查询条件不固定的场景,如用户筛选查询、批量删除等。
- 使用动态 SQL 可以减少冗余代码,避免硬编码多个 SQL 语句。