当前位置: 首页 > news >正文

Mybatis05-动态sql

一、应用场景

MyBatis 的 动态 SQL 是指根据不同的条件动态拼接生成 SQL 语句的能力。它的最大优势是:避免写多个 XML 映射语句、避免 SQL 冗余、提升代码复用性和可维护性

示例1:用户可以通过勾选框,勾选不同的数据进行批量删除,此时:

delete from xxx_table where id in (a, b, c, d, ......)

in后面括号中的数据就是动态的。

示例2:用户搜索功能,查询条件不确定(常用于搜索/筛选)

二、使用方式(XML + 标签)

MyBatis 动态 SQL 主要通过 XML 配置文件中的标签 来实现,核心标签如下:

标签作用
<if>条件判断
<choose> / <when> / <otherwise>类似 Java 中的 if-else if-else
<where>自动加上 WHERE 并避免多余的 AND/OR
<set>用于 UPDATE,自动去除最后的逗号
<foreach>用于遍历集合(常见于 IN、批量插入)
<trim>自定义前缀、后缀、去掉前后符号等

2-1、<if>标签

示例:

    List<Car> selectByMutiConditions(@Param("brand") String brand,@Param("guidePrice") Double guidePrice,@Param("carType") String carType);

 

    <select id="selectByMutiConditions" resultType="car">select * from t_car where 1=1/*1. if标签中,test属性是必须的,值:表达式(false/true)2. test属性可以使用的是:使用了@Param标签,就用@Param标签指定的参数名;没有使用@Param标签,就用:param1, param2, param3, arg0, arg1, arg2...当使用了pojo,就用pojo中的属性名3. 在mybatis的动态sql中,不能使用&&,只能使用and*/<if test="brand != null and brand != ''">and brand like "%"#{brand}"%"</if><if test="guidePrice != null and guidePrice != ''">and guidePrice > #{guidePrice}</if><if test="carType != null and carType != ''">and carType = #{carType}</if></select>

【注意点】:

1. if标签中,test属性是必须的,值:表达式(false/true)

2. test属性可以使用的是:

  •     使用了@Param标签,就用@Param标签指定的参数名;
  •     没有使用@Param标签,就用:param1, param2, param3, arg0, arg1, arg2...
  •     当使用了pojo,就用pojo中的属性名

3. 在mybatis的动态sql中,不能使用&&,只能使用and

4、为了防止有部分条件不成立的时候,where后面直接拼接了and,需要加上1=1

2-2、<where>标签

它的作用是在生成 SQL 语句时:

  1. 自动去掉首个条件多余的 ANDOR

  2. 当有条件时自动加上 WHERE 关键字

  3. 当没有任何条件时不会生成 WHERE 子句

【注意】:

        <where> 标签只对内容中出现的 第一个 AND/OR 进行清理,建议把每个 <if> 条件前都加上 AND,它会自动清理第一个多余的。

示例:

 

2-3、<trim>标签

在 MyBatis 中,<trim> 是一个功能非常强大的 动态 SQL 标签,它可以灵活地控制:

  • 前缀(prefix):开头加什么

  • 后缀(suffix):结尾加什么

  • 前缀去除(prefixOverrides):去掉开头多余的关键字,比如 AND / OR / ,

  • 后缀去除(suffixOverrides):去掉结尾多余的内容,比如 ,


你可以把 <trim> 看成 <where><set> 的“底层基础版本”,功能更灵活。


1、常见属性说明

属性名说明
prefix给内容加上前缀,比如 "WHERE""SET"
suffix给内容加上后缀
prefixOverrides去除内容前面多余的前缀(如多余的 "AND""OR"
suffixOverrides去除内容最后多余的后缀(如多余的 ","

【注意】:

它们 都是在整体 trim 内容拼接完毕后一次性处理整个 SQL 片段的前缀和后缀! 


示例 1:动态 WHERE 条件,代替 <where>

<select id="selectUser" parameterType="User" resultType="User">SELECT * FROM user<trim prefix="WHERE" prefixOverrides="AND |OR "><if test="username != null"> AND username = #{username} </if><if test="gender != null"> AND gender = #{gender} </if></trim>
</select>

效果(如果 username != null 且 gender == null):

SELECT * FROM user WHERE username = 'Tom'

自动去掉多余的 AND,和 <where> 效果一样,但更灵活(你也可以换成 OR)。


示例 2:动态更新字段,代替 <set>

<update id="updateUser" parameterType="User">UPDATE user<trim prefix="SET" suffixOverrides=","><if test="username != null"> username = #{username}, </if><if test="gender != null"> gender = #{gender}, </if></trim>WHERE id = #{id}
</update>

效果:

  • 如果 username = 'Tom', gender = null:

    UPDATE user SET username = 'Tom' WHERE id = 1
    

    自动去掉最后多余的逗号 ,


示例 3:完全自定义的 SQL 拼接

<trim prefix="(" suffix=")" suffixOverrides=","><foreach collection="ids" item="id">#{id},</foreach>
</trim>

输出示例:

(1, 2, 3)

2-4、<set>标签

<set> 标签的作用是:

  • 自动添加 SET 关键字

  • 自动去除多余的结尾逗号 ,

  • <if> 标签组合使用,实现根据条件动态更新字段

目的:希望更新的时候,只更新不为null的字段,其余字段不动!

 

2、基本语法结构

<update id="updateUser" parameterType="User">UPDATE user<set><if test="username != null"> username = #{username}, </if><if test="email != null"> email = #{email}, </if><if test="age != null"> age = #{age}, </if></set>WHERE id = #{id}
</update>

3、执行逻辑过程

假设只传了 usernameageemail 是 null。

MyBatis 会生成这样的 SQL:

UPDATE user
SET username = ?, age = ?
WHERE id = ?

注意:

  • ✅ 自动添加了 SET

  • ✅ 自动移除了末尾多余的 ,


4、和 <trim> 的关系

<set> 本质上就是 <trim> 的封装版本

等价于:

<trim prefix="SET" suffixOverrides=",">...
</trim>

也就是说,如果你希望自定义更多行为(如不使用 SET、用别的关键字),可以改用 <trim> 标签

2-5、<choose>、<when>、<otherwise>

MyBatis 中的 <choose> 标签是用来实现 类似 Java 中 if-else if-else 结构的动态 SQL 分支选择语句,非常适合你有多个条件分支,但只想执行其中一个的情况


1、 作用:

<choose> 是 MyBatis 提供的一个逻辑分支标签,用来表示:

如果满足第一个条件就执行它,否则判断第二个条件……都不满足则执行默认分支。

它的结构和 Java 中的 if ... else if ... else 是一致的:

if (a != null) {// ...
} else if (b != null) {// ...
} else {// default
}

在 MyBatis 中写法如下:

<choose><when test="a != null">...</when><when test="b != null">...</when><otherwise>...</otherwise>
</choose>

2、使用示例

例子:根据传入的条件查询用户

<select id="findUser" parameterType="map" resultType="User">SELECT * FROM user<where><choose><when test="id != null">id = #{id}</when><when test="username != null">username = #{username}</when><otherwise>gender = 'male'</otherwise></choose></where>
</select>

3、执行逻辑:

假设传入参数是:

Map<String, Object> param = new HashMap<>();
param.put("username", "Tom");

生成的 SQL 就是:

SELECT * FROM user WHERE username = 'Tom'

如果传入参数是:

param.put("id", 123);
param.put("username", "Tom");

优先满足第一个条件:

SELECT * FROM user WHERE id = 123

如果两个都没传,则使用 otherwise

SELECT * FROM user WHERE gender = 'male'

4、几点注意事项

特性说明
<choose> 内只能选中 一个 <when> 被执行只执行第一个匹配成功的 <when>
<otherwise> 是可选的不写也可以
多个 <when> 的顺序很重要从上往下匹配,匹配到就停

2-6、<foreach>标签

MyBatis 中的 <foreach> 标签是动态 SQL 中非常重要的一个标签,主要用于 遍历集合(如 List、数组、Map)生成一段重复的 SQL 语句,特别适合用于:

批量插入、批量删除、IN (...) 条件语句


1、 的核心作用

用来遍历集合(如 List数组Map),在 SQL 中动态生成重复片段,比如:

  • id IN (1, 2, 3)

  • 多行 VALUES 插入

  • 多个字段拼接


2、常见属性说明

属性名说明
collection要遍历的集合名,如 listarraymap
item遍历过程中每一项的变量名
index当前项的下标可选
open开始拼接的前缀(如 (
close拼接结束的后缀(如 )
separator每项之间的分隔符(如 ,

3、经典使用场景

(1). IN (...) 查询
<select id="selectByIds" parameterType="list" resultType="User">SELECT * FROM userWHERE id IN<foreach collection="list" item="id" open="(" separator="," close=")">#{id}</foreach>
</select>

传入:

List<Integer> ids = Arrays.asList(1, 2, 3);

生成 SQL:

SELECT * FROM user WHERE id IN (1, 2, 3)

(2). 批量插入
<insert id="insertUsers" parameterType="list">INSERT INTO user (username, age)VALUES<foreach collection="list" item="u" separator=",">(#{u.username}, #{u.age})</foreach>
</insert>

【注意】:

此时,属性:open,close都没有写! 

传入:

List<User> users = List.of(new User("Tom", 20),new User("Jerry", 22)
);

生成 SQL:

INSERT INTO user (username, age)
VALUES ('Tom', 20), ('Jerry', 22)

(3). 遍历 Map,实现动态 UPDATE 字段
<foreach collection="map" item="val" index="key">${key} = #{val}
</foreach>

示例:

    int updateForEach(@Param("updateFields") Map<String, Object> updateFields,@Param("id") Long id);

【注意】:

        此时的key用的是${key},因为是数据库字段,不能用#{key},否则拼接的数据库字段会加上字符串!


4、常见坑点提示

问题说明
collection="list"如果参数是 List,要写 "list"(不是写变量名)
<foreach> 必须配合 open/close/separator否则 SQL 拼接可能出错
item=#{} 中的 item 要和声明保持一致否则无法解析参数
避免用 ${} 插值容易引发 SQL 注入问题

2-7、<include>标签

MyBatis 中的 <include> 标签用于 在 XML 映射文件中复用 SQL 片段,类似 Java 中的方法提取,可以提高 SQL 语句的复用性和可维护性。


1、使用场景

  • 多个 SQL 中有相同字段、相同条件、重复的列名等

  • 希望统一维护公共 SQL 内容,避免拷贝粘贴


2、基本语法

1. 定义可复用的 SQL 片段(使用 <sql> 标签)

<sql id="baseColumnList">id, name, age, gender, email
</sql>

2. 引用 SQL 片段(使用 <include> 标签)

<select id="selectAll" resultType="User">SELECT<include refid="baseColumnList" />FROM users
</select>

3、完整示例

<!-- 定义通用字段列表 -->
<sql id="baseColumnList">id, name, age, gender, email
</sql><!-- 使用 include 引用 -->
<select id="selectById" resultType="User">SELECT <include refid="baseColumnList" />FROM usersWHERE id = #{id}
</select>

4、refid 范围说明

  • <sql id="...">id 必须在当前命名空间中唯一

  • 如果跨命名空间使用,需要使用 namespace.id 引用,例如:

<include refid="com.example.mapper.UserMapper.baseColumnList" />

⚠️ 注意事项

  • 不支持 <sql> 中再嵌套 <sql><include>!!!

http://www.dtcms.com/a/280475.html

相关文章:

  • 深度解析 AI 提示词工程(Prompt Engineering)
  • 2025世界机器人大赛ICode专属训练平台图形化小学组答案
  • 光伏设计全方位指南
  • B/S 架构通信原理详解
  • sqli-labs靶场通关笔记:第17关 POST请求的密码重置
  • 如何配置maven
  • 【Linux手册】重定向是如何实现的?Linux下为什么一切皆文件?
  • flutter下的webview适配rem问题
  • 【NBA】75 Greatest NBA Players of All Time
  • 春秋云镜 initial
  • Uniapp动态切换主题与老年模式详解
  • 12.6 Google黑科技GShard:6000亿参数MoE模型如何突破显存限制?
  • Zen:一款简洁高效、注重隐私的开源浏览器
  • 小白学HTML,操作HTML网页篇(1)
  • 密码工程原理与技术——总复习
  • 灰度图像,RGB图像和二值图像
  • 从OSI到TCP/IP:Linux网络架构深度解析
  • react - 根据路由生成菜单
  • 多模态大模型研究每日简报(2025-07-14)
  • AI应用服务
  • 整除分块练习题
  • 某地金属矿山自动化监测服务项目
  • Python 数据建模与分析项目实战预备 Day 6 - 多模型对比与交叉验证验证策略
  • 2.【C# in .NET】探秘数据类型:从底层机制到实战启示
  • MySQL高级篇(二):深入理解数据库事务与MySQL锁机制
  • 农村养老模式:乡土智慧与时代创新的共生之路
  • 【每日算法】专题十_字符串
  • PySpark Standalone 集群
  • react native学习record one month
  • Flink SQL 性能优化实战