<where>和<set>是MyBatis通过trim封装的SQL结构化标签,分别自动处理WHERE条件开头冗余和SET赋值末尾逗号,确保语法合法;二者不拼接字符串,而是智能控制SQL片段完整性。

<where> 和 <set> 不是“自动拼接”字符串,而是 MyBatis 在解析 SQL 时智能生成合法 SQL 片段的专用标签。它们不靠字符串拼接,而是通过内部逻辑控制 SQL 结构的完整性——比如去掉多余关键字、补全前缀、剔除尾部符号。
下面直接说清楚它们怎么工作、怎么写才不出错:
where 标签:让 WHERE 条件不报语法错误
作用:解决多条件查询中 AND/OR 开头、空 WHERE、或多个条件间连接符混乱的问题。
它会做三件事:
• 如果所有
• 只保留第一个有效条件前的 AND/OR,自动删掉开头多余的 AND;
• 对中间或结尾的 AND/OR 不做处理,只管“开头清理”和“整体存在性”。
示例:
立即学习“Java免费学习笔记(深入)”;
<select id="findUser" resultType="User">
SELECT * FROM user
<where>
<if test="name != null and name != ''">AND name LIKE CONCAT('%', #{name}, '%')</if>
<if test="status != null">AND status = #{status}</if>
<if test="startTime != null and endTime != null">AND create_time BETWEEN #{startTime} AND #{endTime}</if>
</where>
</select>
如果只传了 status,最终 SQL 是:
SELECT * FROM user WHERE status = ?
没有开头的 AND,也没有空 WHERE。
set 标签:让 UPDATE 字段赋值不带多余逗号
作用:专为 UPDATE 语句设计,避免手动写逗号导致语法错误(如 SET name=?, , age=?)。
它会做三件事:
• 自动加上 SET 关键字;
• 只对非空条件内的字段生成赋值语句;
• 自动删掉最后一个逗号(不管它出现在哪一行末尾)。
示例:
立即学习“Java免费学习笔记(深入)”;
<update id="updateUser" parameterType="User">
UPDATE user
<set>
<if test="username != null and username != ''">username = #{username},</if>
<if test="email != null and email != ''">email = #{email},</if>
<if test="age != null">age = #{age}</if>
</set>
WHERE id = #{id}
</update>
如果只更新 email,生成的是:
UPDATE user SET email = ? WHERE id = ?
不会出现 SET , email = ? 或 SET email = ?, 这类错误。
底层原理:它们其实是 trim 的封装
<where> 等价于:
<trim prefix="WHERE" prefixOverrides="AND |OR ">...</trim>
<set> 等价于:
<trim prefix="SET" suffixOverrides=",">...</trim>
也就是说,它们不是黑盒,而是 <trim> 的语义化别名——一个专注 WHERE,一个专注 SET。需要更灵活控制(比如自定义前缀、多符号截断),就直接用 <trim>。
关键提醒:别漏掉 WHERE 条件
<set> 再安全,也防不住没写 WHERE 导致全表更新。务必确保每个 UPDATE 语句都带明确的 WHERE 子句,尤其是主键或唯一约束字段。线上事故里,90% 的误更新都源于此。


















