这是我参与8月更文挑战的第10天,活动详情查看:8月更文挑战
动态SQL
所谓动态SQL,就是根据我们传入的不同参数来动态构造不同的SQL语句,而MyBatis就为我们提供了9个动态标签,来实现动态SQL。
sql、inclue标签
sql标签可以用来抽取重复的sql语句,可以在其他SQL语句块中进行复用,使用include标签引用公用的sql语句块
<!--可以使用以下配置,抽取重复的sql语句-->
<sql id="field" >
/*如果被抽取的语句后面还有其他的拼接语句,则被抽取的语句后面就不能加分号*/
username,birthday,sex,address
</sql>
例如:
<!--配置查询所有-->
<select id="findAll" resultType="user">
select
<include refid="field"></include>
from user
</select>
if标签
if标签可以实现根据实体类的不同取值,使用不同的SQL语句来进行查询。比如在id不为空时可以根据id查询,如果username不为空时还要加入用户名作为查询条件。这种情况在多条件组合查询中经常会碰到。
- if标签的属性test:用于条件判断,使用 OGNL 表达式,如果传入参数满足test中的OGNL表达式,则将if标签对应内容动态拼接到SQL语句上。
<!--根据条件查询-->
<select id="findByCondition" resultType="user">
select *from user where 1=1
<if test="username!=null">
<!--如果传入的username不为空,则是将username作为条件进行查询-->
and username=#{username}
</if>
<if test="address!=null">
<!--如果传入的address不为空,则将其作为查询条件-->
and address=#{address}
</if>
</select>
- 以上例子如果传入userame="12",age=22参数,则拼接后的SQL语句为:
select * from user where 1=1 and username="12" and age=22
where标签
前面的if标签,我们可以看到在where的后面都加了一个"1=1",因为单纯使用if标签,没有办法将第一个条件连接词and剔除掉,所以需要在where之后带上一个"1=1",确保后续条件能够正确拼接,而有了where标签后,where标签会将非首个if标签成立的查询条件的连接词and或者or前缀剔除掉,因此就无需在写"1=1"了。
<!--根据条件查询-->
<select id="findByCondition" resultType="user">
select *from user
<where>
<if test="username!=null">
<!--如果传入的username不为空,则是将username作为条件进行查询-->
username=#{username}
</if>
<if test="address!=null">
<!--如果传入的address不为空,则将其作为查询条件-->
and address=#{address}
</if>
</where>
</select>
- 以上例子如果只传入age=22参数,则拼接后的SQL语句为:
select * from user where age=22
set标签
set标签类似于where标签,在前面我们讲到了where标签会将非首个if标签成立的查询条件的连接词and或者or前缀剔除掉,而当我们使用update语句中使用if标签时,如下:
<update id="updateUser">
update user set
<if test="username!=null">
username=#{username},
</if>
<if test="sex!=null">
sex=#{sex},
</if>
<if test="address!=null">
address=#{address}
</if>
where id=1
</update>
从以上update语句中,我们可以发现,当最后一个if标签中的条件不成立时,最后拼接成的SQL语句为:update user set username=?,sex= ? , where id=1,很明显,sex=?后面多了一个逗号,会出现语法错误,所以set标签就可以自动帮我们将非首个成立的if语句中对应的代码块的前缀逗号给剔除掉或非最后一个成立的if语句中对应的代码块的后缀逗号给剔除掉。
- 使用set标签
<update id="updateUser">
update user
<set>
<if test="username!=null">
username=#{username},
</if>
<if test="sex!=null">
sex=#{sex},
</if>
<if test="address!=null">
address=#{address}
</if>
</set>
where id=1
</update>
- 如上,当我们传入的参数只有username和sex时,address为null,在set标签的帮助下,生成的SQL语句为:
update user set username=?,sex= ? where id=1,如果我们传入的参数为sex,address,username为null,则生成的SQL语句为:update user set sex=? , address=? where id=1
trim标签
trim标签是一个格式化的标签,主要用于拼接sql的条件语句将指定的前缀或后缀的添加或忽略,可以完成set或者是where标记的功能。
trim标签具有如下几个属性
-
prefix:在trim标签内sql语句加上指定前缀 -
suffix:在trim标签内sql语句加上指定后缀 -
prefixOverrides:指定去除多余的前缀内容,如prefixOverrides=“and | or”,去除trim标签内sql语句多余的前缀"and"或者"or"。 -
suffixOverrides:去除指定的多余的后缀内容。如suffixOverrides=“and | or”,去除trim标签内sql语句多余的后缀"and"或者"or"。
例子
- 如在update语句中,trim标签的应用,去除指定后缀:
<update id="trimTest" parameterType="Object">
update user set
//会去除多于的逗号后缀
<trim suffixOverrides=",">
<if test="username != null">
username=#{username},
</if>
<if test="sex != null">
sex11zhidin=#{sex},
</if>
</trim>
where id=#{id}
</update>
- 如,在select中trim的应用,去除指定的前缀
<select id="trimTest">
select * from user where
//会去除多于的and前缀
<trim prefixOverrides="and | or">
<if test="username != null">
and username=#{username}
</if>
<if test="sex != null">
and sex11zhidin=#{sex}
</if>
</trim>
</select>
- 如在insert语句中添加指定的前缀、后缀,剔除指定的后缀
<insert id="insert" parameterType="Object">
insert into user
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="username != null">
username,
</if>
<if test="sex != null ">
sex,
</if>
</trim>
<trim prefix="values(" suffix=")" suffixOverrides=",">
<if test="username != null">
#{username},
</if>
<if test="sex != null">
#{sex},
</if>
</trim>
</insert>
foreach标签
foreach标签用于遍历集合或者数组。
-
collection:代表要遍历的集合,它可以是一个Array数组,List集合、Map集合的键等。当你传入的是一个array数组时,该值为array;当为List集合时,该值为list;当传入的是一个Map集合时,collection的属性值为Map的键。 -
open:代表语句开始的部分 -
close:代表结束部分 -
item:代表遍历集合的每个元素,即本次遍历获取到的元素,当遍历的是一个Map集合时,index为键、item为键对应的值。 -
separator:代表分隔符 -
index:索引的属性名,为当前元素在集合的位置下标,当遍历的对象是 Map集合时,该值为Map的键key
其应用场景主要有以下三类:
-
构建in条件语句,如查询id在某个集合范围内所对应用户信息
select * from user where id in (?,?,?,?),该sql对应传进去的参数就是一个集合或者数组,因此,我们需要遍历该集合或数组,用集合的每一个元素来构建in条件语句的内容。Java代码:
int [] ids ={42,43,44}; //传入的是array数组 userDao.getUSerByIds(ids);Mapper映射文件:
<select id="findByInids" resultType="user" parameterType="com.demo.domain.QueryVo"> select * from user where <foreach collection="array" open="id in (" close=")" item="id" separator=","> #{id} </foreach> </select> -
以上例子,拼接后的SQL语句为
select * from user where id in (?,?,?,?) -
实现批量插入,如往一个数据库表中一次插入多行记录,在不使用SQL动态标签foreach时,我们可能需要使用循坏来进行一次一条数据的插入,这是非常麻烦的,有了foreach,我们可以很轻松地实现一次多条记录的插入。
Java代码
ArrayList<User> users = new ArrayList<>(); users.add(new User("1",new Date(),"男","china")); users.add(new User("2",new Date(),"男","china")); users.add(new User("3",new Date(),"男","china")); userDao.insert(users);Mapper映射文件
<insert id="insert" keyProperty="id"> insert into user(username,birthday,sex,address) values <foreach collection="list" separator="," item="User"> (#{User.username},#{User.birthday},#{User.sex},#{User.address} </foreach> </insert> -
以上例子拼接后的SQL语句为:
insert into user (username,birthday,sex,address) values (?,?,?,?),(?,?,?,?),(?,?,?,?) -
实现动态更新update,根据Map中的键更新指定的字段,Map的值为更新后指定字段的新值。
Java代码
HashMap<String, String> map = new HashMap<>(); map.put("username","不喝奶茶的Programmer"); userDao.updateByMap(map, 67);Mapper映射文件
<update id="updateByMap" > update user set <foreach collection="_parameter" index="key" item="val" separator=","> ${key}=#{val} </foreach> where id =#{id} </update> -
以上例子拼接后的SQL语句为:
update user set username=? where id =?
🚨注意:注意:使用 foreach 标签时,需要对传入的collection参数进行为空性判断,如果传入的参数为null,那么查询语句就会变为
select * from user where id in (),就会出现错误,因此我们可以用if 标签或where标签和if标签的组合来进行传入参数是否为空的判断。
choose标签
有时候我们并不想应用所有的条件,而只是想从多个选项中选择一个。MyBatis 提供了choose标签,按顺序判断 when 中的条件出否成立,如果有一个成立,则执行对应when中的代码块,后面的when不再判断,choose结束。当 choose 中所有 when的条件都不满则时,则执行 otherwise 中的代码块。类似于 Java 的 switch 语句,choose 为 switch,when 为 case,otherwise 则为 default。
<select id="chooseTest" parameterType="user" resultMap="BaseResultMap">
SELECT * from user
<where>
<choose>
<when test="username!=null">
AND username = #{username}
</when>
<when test="sex!=null">
AND sex = #{sex}
</when>
<otherwise>
AND address = #{address}
</otherwise>
</choose>
</where>
</select>
bind标签
bind标签可以用来声明一个变量,并绑定在一个SQL语句的上下文中,供SQl语句中其他地方的使用,常用于模糊查询(模糊查询可以使用${},当无法阻止SQL注入,也可以使用concat()函数,只有MySQL数据库能使用)。
- MySQL中使用concat()函数实现模糊查询条件语句的拼接,该方式只能用于操作MySQL中的数据。
<select id="bindTest">
select * from user where username like comcat('%',#{username},'%')
</select>
- bind标签例子,bind标签可以实现不受数据库类型的限制。
<select id="bindTest">
<bind name="bindValue" value=" '%' + username + '%' "></bind>
select * from user where uername like #{bindValue}
</select>
- 以上例子拼接成的SQL语句为:
select * from user where username like '%username%';
🏁以上就是对MyBatis动态标签的详细解释,如果有错误的地方,还请留言指正,如果觉得本文对你有帮助那就点个赞👍吧😋😻😍