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 代码中)
    复杂逻辑支持 强(标签嵌套) 弱(需手动处理语法细节)
相关推荐
NineData11 小时前
NineData 迁移评估功能正式上线
数据库·dba
NineData16 小时前
数据库迁移总踩坑?用 NineData 迁移评估,提前识别所有兼容性风险
数据库·程序员·云计算
阿里云大数据AI技术16 小时前
用 SQL 调大模型?Hologres + 百炼,让数据开发直接“对话”AI
sql·llm
赵渝强老师19 小时前
【赵渝强老师】PostgreSQL中表的碎片
数据库·postgresql
全栈老石1 天前
拆解低代码引擎核心:元数据驱动的"万能表"架构
数据库·低代码
倔强的石头_2 天前
kingbase备份与恢复实战(二)—— sys_dump库级逻辑备份与恢复(Windows详细步骤)
数据库
jiayou643 天前
KingbaseES 实战:深度解析数据库对象访问权限管理
数据库
李广坤4 天前
MySQL 大表字段变更实践(改名 + 改类型 + 改长度)
数据库
爱可生开源社区5 天前
2026 年,优秀的 DBA 需要具备哪些素质?
数据库·人工智能·dba
随逸1775 天前
《从零搭建NestJS项目》
数据库·typescript