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 代码中)
    复杂逻辑支持 强(标签嵌套) 弱(需手动处理语法细节)
相关推荐
SelectDB技术团队31 分钟前
Agent 场景动态 JSON 性能拆解:Apache Doris 比 ClickHouse 快 7 倍、比 Elasticsearch 快 2 倍
数据库·clickhouse·elasticsearch·json·apache·日志分析·apache doris
greasyfork38 分钟前
多种数据库管理混乱?Navicat Premium 17 for Mac 统一解决
数据库·mysql·macos·mac
Dream_fly_iboy1 小时前
系统架构设计师之数据库
数据库
风和先行1 小时前
Android 数据库相关学习总结
android·数据库·学习
宠友信息2 小时前
Spring Boot与异步审核构建仿小红书源码内容发布全流程
java·数据库·spring boot·redis·mysql·oracle·uni-app
2401_873479402 小时前
如何识别代理IP和伪装流量?用IP情报工具三步穿透住宅代理伪装
网络·数据库·网络协议·tcp/ip·ip
诚信定制8392 小时前
如何启动 Redis 服务:详细步骤指南
数据库·redis·缓存
AllData公司负责人2 小时前
数据同步平台|AIIData数据中台实现MySQL、Hive、Kafka 一键接入Doris
大数据·数据库·hive·mysql·kafka·实时同步
Edward111111112 小时前
一AI名词
java·开发语言·数据库·学习
hey you~3 小时前
400电话选型技术测评:一个开发视角的线路质量评估方案
运维·网络·数据库·400电话·企业通信