# 动态 SQL 标签语法

动态 SQL 功能,允许我们根据条件动态地构造 SQL 语句。通过使用特定的标签,我们可以很方便地实现复杂的 SQL 逻辑。以下是动态 SQL 的常用标签及其用法。

# 1. if 标签

if 标签用于条件判断,类似于 Java 中的 if 语句。

SELECT * FROM BLOG WHERE state = 'ACTIVE'
<if test="title != null">
  AND title like #{title}
</if>

# 参数示例

{
  "title": "MyBlog"
}

# 解析后的真实 SQL

SELECT * FROM BLOG WHERE state = 'ACTIVE' AND title like ?

# 2. choose、when、otherwise 标签

这些标签类似于 Java 中的 switch 语句。

SELECT * FROM BLOG WHERE state = 'ACTIVE'
<choose>
  <when test="title != null">
    AND title = #{title}
  </when>
  <when test="author != null and author.name != null">
    AND author_name = #{author.name}
  </when>
  <otherwise>
    AND featured = 1
  </otherwise>
</choose>

# 参数示例

{
  "title": "MyBlog",
  "author": {
    "name": "AuthorName"
  }
}

# 解析后的真实 SQL

SELECT * FROM BLOG WHERE state = 'ACTIVE' AND title = ?

# 3. trim、where、set 标签

这些标签用于处理 SQL 语句中的前缀、后缀以及连接词。

# trim 标签

trim 标签可以用于定制化的字符串截取。

SELECT * FROM BLOG 
<trim prefix="WHERE" prefixOverrides="and |or ">
  <if test="title != null">
    and title like #{title}
  </if>
  <if test="author != null">
    and author_name like #{author.name}
  </if>
</trim>

# 参数示例

{
  "title": "MyBlog",
  "author": {
    "name": "AuthorName"
  }
}

# 解析后的真实 SQL

SELECT * FROM BLOG WHERE title like ? AND author_name like ?

# where 标签

where 标签会动态地在生成的 SQL 语句前加上 where 关键字,并且会删除第一个 andor 关键字。

SELECT * FROM BLOG 
<where>
  <if test="title != null">
    and title like #{title}
  </if>
  <if test="author != null">
    and author_name like #{author.name}
  </if>
</where>

# 参数示例

{
  "title": "MyBlog",
  "author": {
    "name": "AuthorName"
  }
}

# 解析后的真实 SQL

SELECT * FROM BLOG WHERE title like ? AND author_name like ?

# set 标签

set 标签用于动态更新语句,可以智能地添加 SET 关键字,并且删除最后一个逗号。

UPDATE BLOG
<set>
  <if test="title != null">title = #{title},</if>
  <if test="author != null">author_name = #{author.name},</if>
</set>
WHERE id = #{id}

# 参数示例

{
  "title": "MyBlog",
  "author": {
    "name": "AuthorName"
  },
  "id": 123
}

# 解析后的真实 SQL

UPDATE BLOG SET title = ?, author_name = ? WHERE id = ?

# 4. foreach 标签

foreach 标签主要用于遍历集合,常用于构建 IN 条件。

SELECT * FROM BLOG
WHERE id in
<foreach item="item" index="index" collection="list" open="(" separator="," close=")">
  #{item}
</foreach>

# 参数示例

{
  "list": [1, 2, 3, 4, 5]
}

# 解析后的真实 SQL

SELECT * FROM BLOG WHERE id in (?, ?, ?, ?, ?)

# 5. bind 标签

bind 标签用于创建一个变量,并将 OGNL 表达式的值绑定到该变量。

<bind name="pattern" value="'%' + title + '%'" />
SELECT * FROM BLOG
WHERE title LIKE #{pattern}

# 参数示例

{
  "title": "MyBlog"
}

# 解析后的真实 SQL

SELECT * FROM BLOG WHERE title LIKE ?

# SQL参数引入

在动态 SQL 中,#{}${} 都用于参数引用,但它们在处理参数时存在一些关键区别。

# #{} 的用法

  1. 预编译处理#{} 用于预编译处理,相当于 JDBC 中的 ? 占位符。 会将 #{} 替换为 ?,并进行预编译,然后通过 PreparedStatement 设置参数。
  2. 自动转义#{} 可以有效防止 SQL 注入,因为它会对传入的参数进行自动转义。
  3. 类型处理#{} 可以处理传入参数的类型转换。

示例:

SELECT * FROM BLOG WHERE title LIKE #{title}

传入参数 title = MyBlog 后,解析后的 SQL 为:

SELECT * FROM BLOG WHERE title LIKE ?

# ${} 的用法

  1. 直接替换${} 是直接将参数的值替换到 SQL 语句中,不进行预编译处理。因此,使用 ${} 时需要小心,避免 SQL 注入风险。
  2. 无转义${} 不会对传入的参数进行转义,适用于动态表名或列名。
  3. 类型不转换${} 不经过类型处理器,直接使用参数的 toString() 方法。

示例:

SELECT * FROM BLOG WHERE title LIKE '${title}'

传入参数 title = MyBlog 后,解析后的 SQL 为:

SELECT * FROM BLOG WHERE title LIKE 'MyBlog'

# 使用场景建议

  • 使用 #{}:在大多数情况下,特别是涉及用户输入的场景,应优先使用 #{} 以防止 SQL 注入。
  • 使用 ${}:在需要动态生成表名或列名,并且确保传入参数安全的情况下使用 ${}