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 代码中)
    复杂逻辑支持 强(标签嵌套) 弱(需手动处理语法细节)
相关推荐
betazhou7 小时前
Apache Seatunnel 抽取SQL server实时同步到Oracle-多表同步(五)
数据库·oracle·sqlserver·apache·seatunnel
神也畏惧菠萝7 小时前
Coze 工作流数据库 Day06:架构与高级循环控制的深度技术分析
数据库·架构·llm·coze·coze数据库·数据库流程结构
麦壳饼7 小时前
SonnetDB:空间函数别名的参数与兼容边界
数据库·sonnetdb
花间相见7 小时前
【计算基础|MySQL11】事务与隔离级别
sql·mysql·adb·架构
han68898 小时前
jmeter操作数据库
数据库·jmeter
星马梦缘8 小时前
人工智能学院游戏设计大赛决赛 · 执行提纲
数据库·人工智能·游戏
eleven_4u8 小时前
MySQL引擎层是如何工作的
数据库·mysql
love静思冥想8 小时前
CLOB中JSON查询agent字段值(Oracle11g)
sql·oracle·json
adinnet20269 小时前
企业级 NL2SQL 的重要基础:数据库 Schema 自动理解与元数据管理
数据库
IvorySQL9 小时前
PostgreSQL 日报| OpenCode 遭黑客入侵 API 密钥失窃(10 月 20 日)
数据库·postgresql·区块链