MyBatis学习笔记-07.MyBatis动态Sql语句if、where、trim、set

本文介绍了MyBatis动态SQL中的if、where、trim和set标签的使用,通过实例展示了如何根据条件动态生成SQL语句,以解决查询和更新操作中的条件不确定性问题。在查询时,where标签避免了1=1的冗余,trim标签则可以删除多余的AND或OR并插入WHERE。在更新操作中,set标签动态包含需要更新的列,避免了多余的逗号。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在实际的项目中,经常会遇到动态SQL的增、删、改、查问题,这里我们举一个简单的例子:

在一个web工程中,我们以学生信息为例(表为 stundet),经常会有一个搜索框,并且在搜索之前通常会进行一个关键词的过滤,比如可以过滤的条件有:姓名、性别等,如果当我们姓名和性别都不选,则等价于下面的SQL语句

select * from student

如果我们只填写姓名为"小元",则等价于下面的SQL语句

select * from student where sname="小元"

如果我们同时选中姓名"小元"与性别"男",则等价于下面的SQL语句

select * from student where sname="小元" and sex="男"

当我们有很多的条件时,此时就需要我们去组合这些条件,并动态的生成一个可执行的SQL语句,这样就不是一个简单的SQL语句能够解决问题,那么我们该怎么办呢?在MyBatis中同样是支持这种动态SQL的写法,具体见下面的内容。

一、什么是MyBatis的动态SQL语句:

动态SQL语句可以根据条件智能生成SQL语句,主要用于解决查询条件不确定的情况,在程序运行期间,根据提交的查询条件进行查询,即通过MyBatis提供的各种标签对条件作出判断以实现动态拼接SQL语句

MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么痛苦。拼接的时候要确保不能忘了必要的空格,还要注意省掉列名列表最后的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。

MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑。 

(OGNL表达式:OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,他是一个开源项目。Struts框架使用OGNL作为默认的表达式语言。)

MyBatis中用于实现动态SQL的标签元素主要有:
  • if
  • where
  • set
  • choose(when,otherwise)
  • trim
  • foreach

二、MyBatis的动态SQL语句的使用

数据库表结构如下:


数据库表内容如下


1.if标签元素的使用

例子:从student表中模糊查询 姓名包含"元" 并且 性别为"男"的学生

(1)mapper映射文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yuan.model.Student">
	<select id="queryByIf" parameterType="com.yuan.model.Student" resultType="com.yuan.model.Student">
		select * from student where 1=1
		<if test="sname != null"> 
			and sname like concat('%',#{sname},'%')
		</if>
		<if test="sex != null">
			and sex = #{sex}
		</if>
	</select>
</mapper>

(2)测试程序以及结果如下:


运行成功,此时,我们仅赋值姓名或性别或都不赋值都可正确查询,但每次要在 where后面写 1=1或其他等价条件很烦呀,肿么办?

下面引入第二个标签元素  where

2.where标签元素的使用

(1)mapper映射文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yuan.model.Student">
	<select id="queryByIf" parameterType="com.yuan.model.Student" resultType="com.yuan.model.Student">
		select * from student 
		<where>
			<if test="sname != null">
				and sname like concat('%',#{sname},'%')
			</if>
			<if test="sex != null">
				and sex = #{sex}
			</if>
		</where>
	</select>
</mapper>

(2)测试程序以及结果与上图一致

where的作用:where 元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入“WHERE”子句。而且,若语句的开头为“AND”或“OR”,where 元素也会将它们去除

仅仅会这种方式肿么足够呢?请看我们的万能trim标签元素来实现动态多条件查询!

3.trim标签元素的使用

如果我们不想用 where 1=1 ,更不想受到where标签元素不能为空的约束,我们可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:将多余的AND 或者OR 覆盖,并在其前面加WHERE

<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ... 
</trim>

上述mapper可改为

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yuan.model.Student">
	<select id="queryByIf" parameterType="com.yuan.model.Student"
		resultType="com.yuan.model.Student">
		select * from student
		<trim prefix="WHERE" prefixOverrides="AND |OR ">   
			<if test="sname != null">
				and sname like concat('%',#{sname},'%')
			</if>
			<if test="sex != null">
				and sex = #{sex}
			</if>
		</trim>
	</select>
</mapper>

prefixOverrides 属性会忽略通过管道分隔的文本序列(注意此例中的空格也是必要的,因为怕表中字段有名字包含AND或OR,如Android)。它的作用是移除所有指定在 prefixOverrides 属性中的内容,并且插入 prefix 属性中指定的内容。

运行结果同样正确。

那么动态多条件查询结束,我们又如何进行动态多条件更新呢?那就需要用到我们的set标签元素了(当然配合if标签元素使用)

4.set标签元素的使用

例子:从student表中修改sno为1的学生,修改他的姓名由 大元 到  大大元,修改他的性别由 女 变为 男

更新前数据库表内容:


(1)不使用set标签元素进行更新操作,mapper映射文件内容如下:

在update标签里我们没写parameterType ,parameterType 将会传入这条语句的参数类的完全限定名或别名。
这个属性是可选的,因为 MyBatis 可以通过 TypeHandler 推断出具体传入语句的参数,默认值为 unset。  

parameterType 将会传入这条语句的参数类的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过 TypeHandler 推断出具体传入语句的参数,默认值为 unset。<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yuan.model.Student">
	<update id="updateBySet">  
		<if test="sname != null">
			sname = #{sname},
		</if>
		<if test="sex != null">
			sex = #{sex}
		</if>
		where sno = #{sno}
	</update>
</mapper>

测试程序以及结果:


缺点:在本例中,如果仅传入sname,而不传入sex,则会发生异常


通过观察sql发现,多了一个逗号,所以我们使用set标签元素进行替换

(2)使用set标签元素进行更新操作,mapper映射文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yuan.model.Student">
	<update id="updateBySet">
		update student
		<set>
			<if test="sname != null">
				sname = #{sname},
			</if>
			<if test="sex != null">
				sex = #{sex}
			</if>
		</set> 
		where sno = #{sno}
	</update>
</mapper>

这次我们继续只传入sname,结果如下,无异常:


set 元素可以用于动态包含需要更新的列,而舍去其它的。

set 元素会动态前置 SET 关键字,同时也会删掉无关的逗号,因为用了条件语句之后很可能就会在生成的 SQL 语句的后面留下这些逗号。(和where标签元素一样,要至少有一个子元素的条件返回 SQL 子句,- 没有值我们更新啥-)

刚才我们说trim很全能,那他全能在哪呢?对!更新也可以用它!

(3)使用trim标签元素进行更新操作,mapper映射文件内容如下:将多余的逗号 , 覆盖,并在其前面加SET

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

在本例中:

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yuan.model.Student">
	<update id="updateBySet">
		update student
		<trim prefix="SET" suffixOverrides=",">
			<if test="sname != null">
				sname = #{sname},
			</if>
			<if test="sex != null">
				sex = #{sex}
			</if>
		</trim>
		where sno = #{sno}
	</update>
</mapper>

结果同样正确。

今天暂时整理动态SQL的其中4个标签元素 if、where、trim、set

下一篇将整理剩下的 choose、foreach

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值