MyBatis 的动态 SQL 是其核心特性之一,通过灵活的标签和表达式,允许开发者根据运行时条件动态生成 SQL 语句。以下是其核心作用及具体应用场景:
一、动态 SQL 的核心作用
-
灵活的条件查询
• 按需拼接 SQL:根据参数是否为空动态添加WHERE条件,避免冗余的AND或OR。1
2
3
4
5
6
7
<
select
id
=
"findUser"
resultType
=
"User"
>
SELECT * FROM user
<
where
>
<
if
test
=
"name != null"
>AND name = #{name}</
if
>
<
if
test
=
"age != null"
>AND age = #{age}</
if
>
</
where
>
</
select
>
效果:若name和age均为空,则生成SELECT * FROM user;若仅name有值,则生成WHERE name = ?。
-
减少重复代码
• 避免多条件分支硬编码:通过<choose>/<when>/<otherwise>实现多条件互斥选择,替代多个if-else判断。1
2
3
4
5
6
7
8
9
<
select
id
=
"findUserByType"
>
SELECT * FROM user
WHERE role =
<
choose
>
<
when
test
=
"role == 'admin'"
>'ADMIN'</
when
>
<
when
test
=
"role == 'user'"
>'USER'</
when
>
<
otherwise
>'GUEST'</
otherwise
>
</
choose
>
</
select
>
优势:代码简洁,逻辑清晰,维护成本低。
-
动态批量操作
• 集合遍历生成 SQL:通过<foreach>标签遍历集合,生成IN语句或批量插入。1
2
3
4
5
6
<
select
id
=
"selectByIds"
>
SELECT * FROM user WHERE id IN
<
foreach
collection
=
"ids"
item
=
"id"
open
=
"("
separator
=
","
close
=
")"
>
#{id}
</
foreach
>
</
select
>
应用场景:批量查询、批量更新或删除。
-
防止 SQL 注入
• 参数化绑定:使用#{}占位符自动转义特殊字符,避免拼接字符串导致的注入风险。1
2
<
bind
name
=
"pattern"
value
=
"'%' + name + '%'"
/>
SELECT * FROM user WHERE name LIKE #{pattern}
安全性:即使参数含恶意字符(如' OR 1=1 --),也会被转义为普通字符串。
-
动态更新与字段控制
• 按需更新字段:通过<set>标签动态生成UPDATE语句,避免冗余字段和末尾逗号。1
2
3
4
5
6
7
8
<
update
id
=
"updateUser"
>
UPDATE user
<
set
>
<
if
test
=
"name != null"
>name = #{name},</
if
>
<
if
test
=
"age != null"
>age = #{age},</
if
>
</
set
>
WHERE id = #{id}
</
update
>
效果:仅更新非空字段,减少数据库写入量。
二、典型应用场景
场景 | 动态 SQL 方案 | 效果 |
---|---|---|
多条件查询 | <if>+<where> | 按需生成WHERE子句,避免冗余条件 |
分页查询 | <foreach>+ 分页插件 | 动态生成LIMIT和OFFSET |
批量插入/更新 | <foreach>遍历集合 | 单条 SQL 处理多条数据,减少数据库交互 |
多表关联查询 | <choose>动态选择关联表 | 根据业务需求切换关联逻辑 |
动态排序 | <if>控制ORDER BY字段和方向 | 支持用户自定义排序规则 |
三、动态 SQL 的执行原理
- OGNL 表达式解析:MyBatis 使用 OGNL(Object-Graph Navigation Language)解析动态标签中的条件表达式(如#{name}),将参数映射到 SQL 中。
- SqlNode 组合:动态标签被解析为SqlNode对象(如IfSqlNode、WhereSqlNode),通过组合模式构建完整的SqlSource,最终生成可执行的 SQL。
- 预编译与参数绑定:生成的 SQL 仍使用PreparedStatement进行参数绑定,确保安全性和性能。
四、实际场景示例
场景:多条件搜索用户
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|