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

相关推荐
阿华田5124 分钟前
MySQL性能优化大全
数据库·mysql·性能优化
kaico201811 分钟前
python操作数据库
开发语言·数据库·python
被摘下的星星11 分钟前
MySQL 别名使用规则详解
数据库·mysql
zhangzeyuaaa11 分钟前
Python变量的四种作用域
开发语言·python
墨着染霜华17 分钟前
MySQL 重复数据删除语句
数据库·mysql
ego.iblacat19 分钟前
PostgreSQL 数据库
数据库·postgresql
Hommy8821 分钟前
【开源剪映小助手-客户端】桌面客户端
python·开源·node.js·github·剪映小助手
2501_9216494942 分钟前
2026个人量化交易免费数据API接入:从选型到实操
经验分享·python·金融·api·个人开发·量化交易
wgzrmlrm741 小时前
如何解决ORA-28040没有匹配的验证协议_sqlnet.ora版本兼容设置
jvm·数据库·python
一江寒逸1 小时前
零基础从入门到精通MySQL(附加篇):面试八股文全集
数据库·mysql·面试