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

相关推荐
JQLvopkk13 小时前
C# 轻量级工业温湿度监控系统(含数据库与源码)
开发语言·数据库·c#
玄同76513 小时前
从 0 到 1:用 Python 开发 MCP 工具,让 AI 智能体拥有 “超能力”
开发语言·人工智能·python·agent·ai编程·mcp·trae
小瑞瑞acd13 小时前
【小瑞瑞精讲】卷积神经网络(CNN):从入门到精通,计算机如何“看”懂世界?
人工智能·python·深度学习·神经网络·机器学习
火车叼位14 小时前
也许你不需要创建.venv, 此规范使python脚本自备依赖
python
火车叼位14 小时前
脚本伪装:让 Python 与 Node.js 像原生 Shell 命令一样运行
运维·javascript·python
孤狼warrior14 小时前
YOLO目标检测 一千字解析yolo最初的摸样 模型下载,数据集构建及模型训练代码
人工智能·python·深度学习·算法·yolo·目标检测·目标跟踪
devmoon14 小时前
在 Polkadot Runtime 中添加多个 Pallet 实例实战指南
java·开发语言·数据库·web3·区块链·波卡
Katecat9966314 小时前
YOLO11分割算法实现甲状腺超声病灶自动检测与定位_DWR方法应用
python
认真的薛薛14 小时前
数据库-sql语句
数据库·sql·oracle
爱学英语的程序员15 小时前
面试官:你了解过哪些数据库?
java·数据库·spring boot·sql·mysql·mybatis