JavaEE 进阶第十八期:MyBatis,查询请求的生命周期全景图(三)

专栏:JavaEE 进阶跃迁营

个人主页:手握风云

目录

[一、动态 SQL](#一、动态 SQL)

[1.1. 标签](#1.1. 标签)

[1.2. 标签](#1.2. 标签)

[1.3. 标签](#1.3. 标签)

[1.4.
标签](#1.4. 标签)

[1.5. 标签](#1.5. 标签)

[1.6. 标签](#1.6. 标签)


一、动态 SQL

动态 SQL 是 MyBatis 最强大的特性之一,它的核心在于根据不同条件拼接 SQL 语句。以前使用 JDBC 时,拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。MyBatis 的动态 SQL 通过 OGNL (Object-Graph Navigation Language) 表达式来计算值,并根据结果动态组装 SQL。

1.1. <if> 标签

在注册用户时,有些字段是"必填"的(如用户名、密码),而有些字段是"非必填"的(如性别、年龄、头像等)。果用户没有填写"性别",Java 对象中的 gender 属性就是 null。如果直接拼写固定的 SQL IINSERT INTO user (..., gender) VALUES (..., #{gender}),数据库中可能会插入 null,但如果数据库该字段有默认值(如 '保密'),插入 null 会覆盖掉默认值,这不符合预期。

XML 复制代码
<insert id="insertUserByCondition">
	insert into user_info (username, `password`, age
	<if test="gender != null">
		, gender
	</if>)
	value (#{username}, #{password}, #{age}
	<if test="gender != null">
	    , #{gender}
    </if>)
</insert>
java 复制代码
Integer insertUserByCondition(UserInfo userInfo);
java 复制代码
@Test
void insertUserByCondition() {
    UserInfo userInfo = new UserInfo("Jeff", "Bezos", 62);
    Integer rows = userInfoMapperXML.insertUserByCondition(userInfo);
    System.out.println("影响的行数" + rows);
}

1.2. <trim> 标签

之前的插入用户的功能,只有一个 gender 是选填项。如果有多个字段,一般需要多种标签结合,<trim>标签是 MyBatis 动态 SQL 的核心标签之一,主要用于结合<if>标签处理多字段动态生成 SQL 的场景,解决单<if>标签处理多个选填字段时,SQL 语句拼接出现的多余分隔符、前缀 / 后缀缺失等语法问题,适用于插入、查询等多个 SQL 操作中,是处理多动态字段的优选方案。

<trim> 标签的核心属性:

  1. prefix :为整个 SQL 语句块添加指定前缀
  2. suffix :为整个 SQL 语句块添加指定后缀
  3. prefixOverrides:剔除整个 SQL 语句块开头的指定字符 / 符号;
  4. suffixOverrides:剔除整个 SQL 语句块结尾的指定字符 / 符号。
XML 复制代码
<insert id="insertUserByCondition">
	insert into user_info (
	<if test="username != null">
		username,
	</if>
    <if test="`password` != null">
	    `password`,
    </if>
    <if test="age != null">
	    age
    </if>
	<if test="gender != null">
		, gender
	</if>)
	value (
    <if test="username != null">
	    #{username},
    </if>
    <if test="`password` != null">
	    #{password},
    </if>
    <if test="age != null">
	    #{age}
    </if>
	<if test="gender != null">
	    , #{gender}
    </if>)
</insert>
java 复制代码
@Test
void insertUserByCondition() {
    UserInfo userInfo = new UserInfo();
    userInfo.setUsername("Musk");
    Integer rows = userInfoMapperXML.insertUserByCondition(userInfo);
    System.out.println("受影响的行数:" + rows);
}

这里就会出现 SQL 语法错误,如果我们对于某些字段如果没有传值,就会造成逗号的缺失或者多余。我们可以通过<trim>包裹<if>标签实现字段和值的动态拼接,给两个<trim>均设置prefix="("、suffix=")",拼接 SQL 的括号。

XML 复制代码
<insert id="insertUserByCondition">
	insert into user_info
	<trim suffixOverrides="," suffix=")" prefix="(">
		<if test="username != null">
			username,
		</if>
	    <if test="`password` != null">
		    `password`,
	    </if>
	    <if test="age != null">
		    age
	    </if>
		<if test="gender != null">
			, gender
		</if>
	</trim>
	value
    <trim suffixOverrides="," prefix="(" suffix=")">
	    <if test="username != null">
		    #{username},
	    </if>
	    <if test="`password` != null">
		    #{password},
	    </if>
	    <if test="age != null">
		    #{age}
	    </if>
		<if test="gender != null">
		    , #{gender}
	    </if>
    </trim>
</insert>

1.3. <where> 标签

我们在 YouTube 里面搜索内容,我们可以根据视频的类型、时长进行筛选。我们这里就可以使用 <where> 标签。<where>标签是 MyBatis 动态 SQL 的核心标签之一,核心作用是根据子元素内容动态组装 SQL 的 WHERE 查询条件 ,解决手动拼接 WHERE 子句时易出现的语法错误问题。<where>标签适用于根据传入对象的属性动态生成查询条件的场景,仅将对象中不为 null 的属性作为 WHERE 查询条件,比如根据年龄、性别、删除标识等多可选条件查询用户信息。

java 复制代码
<select id="selectByCondition" resultType="com.yang.test2_11_1.model.UserInfo">
	select  * from user_info where
    <trim prefixOverrides="and">
        <if test="age != null">
	        and age = #{age}
        </if>
        <if test="gender != null">
	        and gender = #{gender}
        </if>
		<if test="deleteFlag != null">
	        and delete_flag = #{deleteFlag}
        </if>
    </trim>
</select>
java 复制代码
@Test
void selectByCondition() {
    UserInfo userInfo = new UserInfo();
    userInfo.setAge(25);
    userInfo.setGender(1);
    userInfo.setDeleteFlag(0);
    List<UserInfo> userInfos = userInfoMapperXML.selectByCondition(userInfo);
    System.out.println(userInfos);
}

如果我们把3个参数值都设为空,那么就会报错。原因是多出一个 where,也就是没有查询条件,我们不能使用 <trim> 去掉。解决方案:在 where 后面加上 1=1;或者使用 <where> 标签,<where> 标签可以取出最前面的 and,如果有查询条件,自动添加 where 关键字。

XML 复制代码
<select id="selectByCondition" resultType="com.yang.test2_11_1.model.UserInfo">
	select  * from user_info
	<where>
		<if test="age!=null">
			and age = #{age}
		</if>
		<if test="gender!=null">
			and gender = #{gender}
		</if>
		<if test="deleteFlag!=null">
			and delete_flag = #{deleteFlag}
		</if>
	</where>
</select>

1.4. <set> 标签

<set>标签是 MyBatis 动态 SQL 的核心标签之一,专门用于 UPDATE 更新语句中,核心作用是动态组装 SET 子句,解决手动拼接更新语句时的语法错误问题。

核心功能:动态在 SQL 语句中插入 set 关键字,且会自动剔除由<if>标签拼接后产生的额外逗号,避免因末尾多余逗号导致的 SQL 语法错误。

在<update>标签内嵌套<set>标签,<set>标签内部通过<if>标签判断每个属性是否非空,非空则拼接对应的字段更新语句,最后通过 where 子句指定更新条件(如主键)。

XML 复制代码
<update id="updateUserByCondition">
	update user_info
	<set>
		<if test="gender != null">
			gender = #{gender}
		</if>
		<if test="deleteFlag != null">
			delete_flag = #{deleteFlag}
		</if>
	</set>
</update>
java 复制代码
@Test
void updateUserByCondition() {
    UserInfo userInfo = new UserInfo();
    userInfo.setId(9);
    userInfo.setGender(1);
    Integer rows = userInfoMapperXML.updateUserByCondition(userInfo);
    System.out.println("受影响的行数:" + rows);
}

1.5. <foreach> 标签

<foreach>是 MyBatis 中用于对 List、Set、Map、数组等集合 / 数组对象进行遍历的动态 SQL 标签,常应用于批量查询、批量删除、批量插入等批量操作场景,能动态拼接遍历后的 SQL 语句块。

属性名 作用说明
collection 绑定方法参数中的集合 / 数组对象,如 List、Set、Map 或数组类型的参数名
item 遍历时,代表集合 / 数组中的每一个元素 / 对象,可通过 #{item 名} 获取值
open 指定遍历生成的 SQL 语句块开头要拼接的字符串
close 指定遍历生成的 SQL 语句块结尾要拼接的字符串
separator 指定遍历过程中,每个元素之间的分隔符(如逗号、and 等)

在<delete>标签内嵌套<foreach>,拼接 IN 条件的 SQL。

XML 复制代码
<delete id="batchDelete">
	delete from user_info where id in
	<foreach collection="ids" open="(" close=")" item="id" separator=",">
		#{id}
	</foreach>
</delete>
java 复制代码
@Test
void batchDelete() {
    List<Integer> ids = List.of(11, 12, 16, 17);
    Integer integer = userInfoMapperXML.batchDelete(ids);
}

注意:collection 属性的值为方法参数的名称 (如上例的ids),需与接口方法的参数名保持一致。

1.6. <include> 标签

<include>标签是 MyBatis 用于解决 XML 映射文件中SQL 片段重复、代码冗余问题的核心标签,需与 <sql> 标签配合使用,实现 SQL 片段的抽离和重用,提升代码的可维护性。

在 XML 映射文件中,多个 SQL 语句常出现重复的片段(如查询语句中相同的字段列表),大量冗余代码会增加维护成本,<include>标签可通过抽离公共 SQL 片段解决该问题。

  • <sql> :用于定义可重用的公共 SQL 片段 ,通过id属性为片段设置唯一标识,供<include>标签引用。
  • <include> :用于引用<sql>标签定义的 SQL 片段 ,通过refid属性指定要引用的<sql>片段的id,实现片段的复用。
相关推荐
时艰.4 小时前
海量数据高并发读写方案设计
java
.小小陈.4 小时前
Python基础语法详解4:函数、列表与元组全解析
开发语言·c++·python·学习
IT猿手4 小时前
多目标鲸鱼优化算法(MOWOA)求解46个多目标函数及一个工程应用,包含四种评价指标,MATLAB代码
开发语言·算法·matlab
wjs20244 小时前
Ruby 条件判断
开发语言
leo_2324 小时前
语言、开发语言&程序设计语言--SMP(软件制作平台)语言基础知识之六十一
开发语言·开发工具·企业信息化·smp(软件制作平台)·应用系统·eom(企业经营模型)
古城小栈4 小时前
Rust中 引用类型 VS 裸指针
开发语言·后端·rust
我命由我123454 小时前
Android多进程开发 - AIDL 参数方向、AIDL 传递自定义对象、AIDL 传递自定义对象(参数方向)
android·java·java-ee·kotlin·android studio·android jetpack·android-studio
SunnyDays10114 小时前
Java 删除与重置 Excel 文件密码(文件级与工作表级完整示例)
java·删除excel文件密码·重置excel文件密码·解除excel工作表保护
Dcs4 小时前
删掉 40 行代码,性能飙 400 倍?OpenJDK 这次把“慢如 /proc”按在地上摩擦!
java