MyBatis 的动态 SQL

1. 动态 SQL 的定义

动态 SQL 是 MyBatis 的核心特性之一,它允许开发者根据运行时条件动态生成 SQL 语句。通过特殊的 XML 标签或注解语法,实现 SQL 的灵活拼接,避免在 Java 代码中手动拼接 SQL 字符串的复杂性和安全风险。

2. 核心作用
  • 条件分支:根据参数值动态包含/排除 SQL 片段(如 WHERE 条件过滤)。

  • 循环处理:遍历集合生成批量操作(如 IN 查询、批量插入)。

  • 智能语法处理 :自动去除多余的 AND/OR 或逗号,保证 SQL 语法正确性。

  • 防止 SQL 注入 :通过参数占位符(#{})预编译 SQL。

3. 常用标签详解
标签 作用 示例
<if> 条件判断,满足条件时包含 SQL 片段 xml <if test="name != null">AND name = #{name}</if>
<choose> 多条件分支(类似 Java 的 switch-case xml <choose><when test="age != null">AND age = #{age}</when><otherwise>AND age > 18</otherwise></choose>
<foreach> 遍历集合(如 List、Array) xml <foreach item="id" collection="ids" open="(" separator="," close=")">#{id}</foreach>
<where> 智能处理 WHERE 子句,自动去除开头的 AND/OR xml <where><if test="name != null">AND name = #{name}</if></where>
<set> 智能处理 UPDATE 语句,自动去除结尾逗号 xml <set><if test="name != null">name = #{name},</if></set>
<trim> 自定义字符串修剪(灵活处理前后缀) xml <trim prefix="WHERE" prefixOverrides="AND">...</trim>
<bind> 创建变量并绑定到上下文(用于模糊查询等) xml <bind name="pattern" value="'%' + keyword + '%'" />
4. 典型应用场景
  1. 多条件组合查询

    XML 复制代码
    <select id="findUsers" resultType="User">
        SELECT * FROM user
        <where>
            <if test="name != null">AND name LIKE #{name}</if>
            <if test="minAge != null">AND age >= #{minAge}</if>
            <if test="maxAge != null">AND age <= #{maxAge}</if>
        </where>
    </select>

    2.批量插入数据

    XML 复制代码
    <insert id="batchInsert">
        INSERT INTO user (name, age) VALUES
        <foreach item="user" collection="list" separator=",">
            (#{user.name}, #{user.age})
        </foreach>
    </insert>

    3.动态更新字段

    XML 复制代码
    <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>
5. 优势分析
优势 说明
代码简洁 避免 Java 代码中复杂的 StringBuilder 拼接
可维护性强 SQL 与 Java 代码解耦,修改 SQL 无需重新编译 Java
安全性高 自动使用 PreparedStatement 预编译,防止 SQL 注入
智能语法处理 自动处理逗号、AND/OR 等语法细节
灵活性高 支持复杂逻辑(嵌套条件、循环等)
6. 底层实现原理

MyBatis 动态 SQL 基于 OGNL(Object-Graph Navigation Language)表达式 实现:

  1. 解析 XML 标签时,根据 test 属性中的 OGNL 表达式计算布尔值。

  2. 遍历 SQL 节点树,动态拼接符合条件的 SQL 片段。

  3. 最终生成标准的 PreparedStatement 可执行的 SQL。

7. 最佳实践
  • 避免过度复杂:动态 SQL 嵌套不超过 3 层,否则可拆分为多个查询。

  • 性能优化 :使用 <where><set> 减少无效字符处理开销。

  • 参数校验:在 Java 层校验参数合法性,减少动态 SQL 判断分支。

  • 注解替代 XML :简单场景可用 @SelectProvider 注解实现动态 SQL:

    java 复制代码
    @SelectProvider(type = UserSqlBuilder.class, method = "buildQuery")
    List<User> findUsers(UserQuery query);
    
    class UserSqlBuilder {
        public String buildQuery(UserQuery query) {
            return new SQL() {{
                SELECT("*");
                FROM("user");
                if (query.getName() != null) WHERE("name = #{name}");
            }}.toString();
        }
    }
    8. 对比其他方案
    方案 动态 SQL Java 拼接 SQL
    可读性 高(结构化标签) 低(大量字符串拼接)
    安全性 高(自动预编译) 低(易引发 SQL 注入)
    维护成本 低(SQL 独立管理) 高(SQL 散落在 Java 代码中)
    复杂逻辑支持 强(标签嵌套) 弱(需手动处理语法细节)
相关推荐
凌睿马1 分钟前
关于复杂数据结构从MySQL迁移到PostgreSQL的可行性
数据结构·数据库·mysql
是一个Bug16 分钟前
声明式事务:深度解析与实战指南
数据库·oracle
laocooon52385788625 分钟前
C#二次开发中简单块的定义与应用
android·数据库·c#
不穿格子的程序员26 分钟前
Redis篇4——Redis深度剖析:内存淘汰策略与缓存的三大“天坑”
数据库·redis·缓存·雪崩·内存淘汰策略
IT枫斗者37 分钟前
Netty的原理和springboot项目整合
java·spring boot·后端·sql·科技·mysql·spring
hans汉斯44 分钟前
【软件工程与应用】平移置换搬迁系统设计与实现
数据库·人工智能·系统架构·软件工程·汉斯出版社·软件工程与应用
gugugu.1 小时前
Redis List类型完全指南:从原理到实战应用
数据库·redis·list
Hello.Reader1 小时前
Flink SQL ALTER 语句在线演进 Table/View/Function/Catalog/Model
数据库·sql·flink
白学还是没白学?1 小时前
exec db docker from A to B
数据库·docker·容器