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 代码中)
    复杂逻辑支持 强(标签嵌套) 弱(需手动处理语法细节)
相关推荐
神龙天舞200117 分钟前
MySQL 备库为什么会延迟好几个小时
android·数据库·mysql
丙氨酸長鏈2 小时前
Web前端入门第 问:JavaScript 一个简单的 IndexedDB 数据库入门示例
前端·javascript·数据库
独行侠影a2 小时前
APScheduler+Redis 分布式定时任务:解决多实例任务重复执行
数据库·redis·分布式
传说故事3 小时前
数据库中一些常用英文单词含义
数据库·oracle
夏贰四3 小时前
中小企业搭建业务中台如何控成本?业务中台轻量化落地分几步实施?
数据库·业务中台
林焱RPA3 小时前
影刀RPA200篇纪念版:最实用的20个自动化场景大盘点
数据库
名字还没想好☜3 小时前
Go 的 time.After 在 select 循环里内存泄漏:定时器堆积原理与 timer.Reset 正确姿势
java·数据库·golang·go·goroutine
每天都要进步哦5 小时前
SQL单行函数详解:字符、数字、日期、转换与通用函数全解析
数据库·mysql
不剪发的Tony老师5 小时前
VeloxDB:一款免费开源的轻量级数据库管理工具
数据库·sql
dotnet906 小时前
批量生成所有表的修改脚本
数据库·sql·oracle