MyBatis 的动态 SQL 是其核心特性之一,通过灵活的标签和表达式,允许开发者根据运行时条件动态生成 SQL 语句。以下是其核心作用及具体应用场景:
一、动态 SQL 的核心作用
-
灵活的条件查询
• 按需拼接 SQL:根据参数是否为空动态添加WHERE条件,避免冗余的AND或OR。1
2
3
4
5
6
7
<selectid="findUser"resultType="User">SELECT * FROM user<where><iftest="name != null">AND name = #{name}</if><iftest="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
<selectid="findUserByType">SELECT * FROM userWHERE role =<choose><whentest="role == 'admin'">'ADMIN'</when><whentest="role == 'user'">'USER'</when><otherwise>'GUEST'</otherwise></choose></select>优势:代码简洁,逻辑清晰,维护成本低。
-
动态批量操作
• 集合遍历生成 SQL:通过<foreach>标签遍历集合,生成IN语句或批量插入。1
2
3
4
5
6
<selectid="selectByIds">SELECT * FROM user WHERE id IN<foreachcollection="ids"item="id"open="("separator=","close=")">#{id}</foreach></select>应用场景:批量查询、批量更新或删除。
-
防止 SQL 注入
• 参数化绑定:使用#{}占位符自动转义特殊字符,避免拼接字符串导致的注入风险。1
2
<bindname="pattern"value="'%' + name + '%'"/>SELECT * FROM user WHERE name LIKE #{pattern}安全性:即使参数含恶意字符(如' OR 1=1 --),也会被转义为普通字符串。
-
动态更新与字段控制
• 按需更新字段:通过<set>标签动态生成UPDATE语句,避免冗余字段和末尾逗号。1
2
3
4
5
6
7
8
<updateid="updateUser">UPDATE user<set><iftest="name != null">name = #{name},</if><iftest="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 |
|
2051

被折叠的 条评论
为什么被折叠?



