(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 个,你就能应付绝大多数业务场景!

相关推荐
雨晨源码(同名B站)15 分钟前
基于Python的网易云音乐评论数据情感化分析系统 音乐爬虫信息可视化 |SnowNLP评论情感分析
开发语言·hadoop·爬虫·python·信息可视化·毕业设计
阿童木写作17 分钟前
跨境电商图片翻译工具推荐:跨马翻译批量处理视频字幕与抠图
python·音视频
m0_4626052222 分钟前
大模型week02
数据库
DBA_G36 分钟前
GBase 8a数据库集群多维度资源管控策略矩阵解析
数据库·oracle
怪奇云呼军1 小时前
G.711、Opus 和重采样会拖慢识别吗?闪电智能VoiceAgent 的音频入口怎么选
java·人工智能·python·算法·云计算·音视频
ZC跨境爬虫1 小时前
LeetCode 27. 移除元素(双指针详解 + Java Python 多解法对比)
java·python·leetcode
Patrick在香港1 小时前
Python正则表达式实战:解析和验证香港身份证、车牌、电话格式
开发语言·python·正则表达式
路溪非溪2 小时前
Python语言的执行流程总结
开发语言·python
逐米时代2 小时前
智能招聘与人岗匹配:可解释匹配让录用依据有迹可循
大数据·数据库·人工智能
承渊政道2 小时前
KES专业技能包发布:覆盖数据库开发、迁移与运维全流程
运维·数据库·gitee·数据库开发·金仓数据库