(15)动态SQL中的if,foreach和一些其他的常用标签

✅ 一、为什么需要动态 SQL?

静态 SQL 无法应对:

  • 条件搜索(用户可能只填部分字段)
  • 批量插入/更新
  • 复杂 WHERE / SET 逻辑

MyBatis 提供了强大的标签体系,在 XML 中写"类 Java 逻辑" ,但安全(预编译)且高效


🔥 二、最常用动态 SQL 标签(按使用频率排序)

1. <if> ------ 条件判断(90% 场景都用它)

xml 复制代码
<select id="searchUsers" resultType="User">
  SELECT * FROM user
  <where>
    <if test="name != null and name != ''">
      AND name LIKE CONCAT('%', #{name}, '%')
    </if>
    <if test="age != null">
      AND age = #{age}
    </if>
  </where>
</select>

关键点

  • test 表达式支持 OGNL(类似 Java 表达式)
  • 必须配合 <where> :自动去掉第一个 AND,避免语法错误

2. <foreach> ------ 循环(批量操作必备)

场景1:IN 查询
xml 复制代码
<select id="selectByIds" resultType="User">
  SELECT * FROM user
  <where>
    <foreach collection="ids" item="id" open="id IN (" separator="," close=")">
      #{id}
    </foreach>
  </where>
</select>

调用:userMapper.selectByIds(Arrays.asList(1, 2, 3));

场景2:批量插入
xml 复制代码
<insert id="batchInsert">
  INSERT INTO user (name, email) VALUES
  <foreach collection="users" item="user" separator=",">
    (#{user.name}, #{user.email})
  </foreach>
</insert>

属性说明

  • collection:传入的集合(List / Array / Map 的 key)
  • item:循环变量名
  • open / close:包裹前后
  • separator:分隔符

3. <where> ------ 智能处理 WHERE 子句

自动:

  • 去掉开头的 ANDOR
  • 如果内部无有效条件,整个 <where> 不生成
xml 复制代码
<where>
  <if test="name != null">AND name = #{name}</if>
  <if test="age != null">AND age = #{age}</if>
</where>

→ 无条件时:SELECT * FROM user(正确!)

→ 有 name 时:SELECT * FROM user WHERE name = ?(自动去 AND)

❌ 不要手写 WHERE 1=1!这是反模式。


4. <set> ------ 智能 UPDATE

自动:

  • 去掉末尾的逗号
  • 如果无更新字段,不生成 SET
xml 复制代码
<update id="updateUser">
  UPDATE user
  <set>
    <if test="name != null">name = #{name},</if>
    <if test="email != null">email = #{email},</if>
  </set>
  WHERE id = #{id}
</update>

5. <choose>, <when>, <otherwise> ------ 类似 Java 的 switch

xml 复制代码
<select id="searchUsers" resultType="User">
  SELECT * FROM user
  <where>
    <choose>
      <when test="name != null">
        name LIKE CONCAT('%', #{name}, '%')
      </when>
      <when test="email != null">
        email = #{email}
      </when>
      <otherwise>
        status = 'ACTIVE'
      </otherwise>
    </choose>
  </where>
</select>

✅ 适用于 互斥条件(只满足一个)


6. <trim> ------ 万能裁剪(底层实现 <where><set> 的基础)

xml 复制代码
<!-- 等价于 <where> -->
<trim prefix="WHERE" prefixOverrides="AND |OR ">
  <if test="...">...</if>
</trim>

<!-- 等价于 <set> -->
<trim prefix="SET" suffixOverrides=",">
  <if test="...">...</if>
</trim>

💡 一般不用直接写 <trim>,除非有特殊需求。


⚠️ 三、大厂避坑指南(Code Review 高频问题)

问题 正确做法
SQL 注入 永远用 #{}不要用 ${} 拼接条件值(除非是表名/列名,且严格校验)
空集合导致语法错误 <foreach> 前加 <if test="list != null and !list.isEmpty()">
性能差的模糊查询 LIKE CONCAT('%', #{name}, '%') → 考虑全文索引或 ES
过度动态 SQL 复杂逻辑拆成多个 Mapper 方法,比一个"万能方法"更清晰

✅ 四、总结:标签速查表

标签 用途 必记要点
<if> 条件判断 配合 <where> / <set>
<foreach> 循环 collection, item, separator
<where> 智能 WHERE 自动处理 AND/OR
<set> 智能 SET 自动去逗号
<choose> 多选一 like switch
<trim> 自定义裁剪 高级用法

💡 终极建议
80% 的动态 SQL 用 <if> + <where> + <foreach> 就够了

先掌握这 3 个,你就能应付绝大多数业务场景!

相关推荐
DB虚空行者8 小时前
聊下几次线上删除MySQL导致的故障
数据库
小鸡吃米…8 小时前
带Python的人工智能——计算机视觉
人工智能·python·计算机视觉
一 乐8 小时前
健身房预约|基于springboot + vue健身房预约小程序系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·学习·小程序
玄同7659 小时前
Python 数据类型:LLM 语料与 API 参数的底层处理逻辑
开发语言·人工智能·python·自然语言处理·llm·nlp·知识图谱
代码游侠9 小时前
学习笔记——IO多路复用技术
linux·运维·数据库·笔记·网络协议·学习
databook9 小时前
数据分析师的“水晶球”:时间序列分析
python·数据挖掘·数据分析
云飞云共享云桌面9 小时前
河北某机器人工厂8个研发设计共享一台SolidWorks云主机
运维·服务器·网络·数据库·算法·性能优化·机器人
FixPng10 小时前
【数据库】MySQL基于MyCAT分库分表
数据库·mysql
技术路上的探险家10 小时前
vLLM常用启动参数的详细解释
python·大模型·qwen·vllm
WHJ22610 小时前
记录解决jupyter打开闪退
ide·python·jupyter