本篇主要介绍MyBatis动态sql的部分
目录
一、if标签
二、trim标签
三、where标签
四、set标签
五、foreach标签
六、include标签
七、在注解里使用动态sql
一、if标签
平常我们在使用某些软件时,需要填写自己的个人信息,但在个人信息中,通常有些是必填的,有些则是非必填的,这样就会导致传到后端的数据可能会随机缺某个属性,这样就使得在编写sql时不知道具体要插入哪个数据,此时就需要使用if标签了,在标签中写需要动态变化的sql,在标签中有一个test属性,它里面是一个判断条件(判断的是对象的属性值),只有条件为true,才会在sql中拼接动态部分的sql。具体代码示例如下:
<insert id="addUser" useGeneratedKeys="true" keyProperty="id">
insert into userinfo
(username,
password,
<if test="gender != null">gender,</if>
phone,
age)
values(#{username},
#{password},
<if test="gender != null">#{gender},</if>
#{phone},
#{age})
</insert>
在这个代码中gender属性是非必填的,因此这个属性可能有值也可能为空,所以使用用if标签来控制,只有gender属性不为空时才在sql中加上gender这个字段。我们来测试一下这个代码。
我们先看看给gender传值的情况:
可以发现此时是有gender字段的。
然后我们再来看一下不传的情况:
可以发现sql中没有gender了。因此我们可以使用if标签来控制是否要在sql中添加某部分sql 。
二、trim标签
在使用<if>标签时,可能会出现这样一种情况:
<insert id="addUser" useGeneratedKeys="true" keyProperty="id">
insert into userinfo
(<if test="username != null">username,</if>
<if test="password != null">password,</if>
<if test="gender != null">gender,</if>
<if test="phone != null">phone,</if>
<if test="age != null">age,</if>)
values(<if test="username != null">#{username},</if>
<if test="password != null">#{password},</if>
<if test="gender != null">#{gender},</if>
<if test="phone != null">#{phone},</if>
<if test="age != null">#{age},</if>)
</insert>
我们来测试一下这段代码,并且里面的每个值都传。
可以发现程序报错了,并且错误是发生在sql上,然后观察日志里打印的实际执行的sql,可以发现sql的后面多了一个 “ ,”,为什么会多个“,”,其实也很简单,仔细观察代码就可以知道,每个拼接的sql后面都会带一个“,”,但这个“,”是不能不加的,不然sql语法就错了,那如果将“,”放前面呢?显然也是不行的,这会在sql前面多加一个“,"。此时就需要使用trim标签了,使用trim标签可以去掉标签内包含的sql的前缀或后缀符号也可以在sql前面加一个前缀或者后缀,因此我们可以使用trim标签,来去掉这里的“,”。具体的示例代码如下:
<insert id="addUser" useGeneratedKeys="true" keyProperty="id">
insert into userinfo
<trim prefix="(" suffix=")" prefixOverrides="," suffixOverrides="," >
<if test="username != null">username,</if>
<if test="password != null">password,</if>
<if test="gender != null">gender,</if>
<if test="phone != null">phone,</if>
<if test="age != null">age,</if></trim>
values
<trim prefix="(" suffix=")" prefixOverrides="," suffixOverrides="," >
<if test="username != null">#{username},</if>
<if test="password != null">#{password},</if>
<if test="gender != null">#{gender},</if>
<if test="phone != null">#{phone},</if>
<if test="age != null">#{age},</if></trim>
其中 prefix属性为要添加的前缀符合,suffix属性为要添加的后缀符合,prefixOverrides为需要删除的前缀符合,而suffixOverrides则是需要删除的后缀符合。下面我们来测试一下:
通过日志可以发现,括号已经被添加了,并且多出的“,”也被删除了。
三、where标签
<where>标签可以动态的为sql添加判断条件,具体代码示例如下:
<select id="selectUserByNameOrId" resultType="com.example.demo.UserInfo">
select * from userinfo
<where>
<if test="username != null">and username = #{username}</if>
<if test="id != null">and id = #{id} </if>
</where>
</select>
这段代码中只要if标签里有一个是成立的,就会自动在sql中生成 一个where,其判断条件为if标签里的内容,并且会自动删除判断条件的sql前面多出的and或者or关键字。下面我们来测试一下:
通过日志可以发现,where和判断条件都添加了 ,并且前面多出的and也已经删除了。
四、set标签
set标签和where标签类似,也是在标签里写if标签,如果有一个以上if标签成立就会自动添加set关键字,并自动去除前导符合,具体代码示例如下:
<update id="updateUserById" >
update userinfo
<set>
<if test="username != null">,username = #{username}</if>
<if test="password != null">,password = #{password}</if>
<if test="gender != null">,gender = #{gender}</if>
<if test="phone != null">,phone = #{phone}</if>
<if test="age != null">,age = #{age}</if>
where id = #{id}
</set>
</update>
然后我们测试一下
根据日志信息可以发现set标签已经发挥作用了。但不推荐这里set和where标签一起用,因为一旦数据忘传或者其他原因导致数据为空使得where标签里if条件都不成立,就会导致表中的数据全部被修改了。
五、foreach标签
在根据id进行查询用户时,有可能会出现要根据多个id来查询用户的情况,如果一个一个去查就会显得十分冗余,此时就推荐使用<foreach>标签,它能让sql获取到接口方法中传入的集合,具体代码示例如下:
<select id="selectUserByIdList" resultType="com.example.demo.UserInfo">
select * from userinfo where id in
<foreach collection="idList" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</select>
其中的collection为集合名称(接口方法里传入的集合对象),item表示集合里每个元素的名称,与标签内#{}里的名称对应,open拼接的sql起始符合,close为结束符合,separator为元素之间的分割符合。
接下来测试一下:
可以通过标签发挥作用了,这样就能根据集合里传入的id,实现一次查询多个了。
六、include标签
在我们编写sql时会出现很多重复的sql,多次重复写就会显的十分麻烦,这不符合程序员“懒”的特性,因此程序员就想出了一个方法,将重复的sql先定义在一个地方,如果要使用这段这段重复的sql直接去这个地方拿就行,<include>就实现了这样的功能。使用<include>时需要先定义一个sql标签,标签里的内容为要重复使用的sql片段,并为sql标签设置一个id属性,用来表示这个片段的名称,如果要使用这个片段,就需要使用到<include>标签,<include>标签里有一个refid属性,将这个属性值设置为前面定义的sql片段的名称,就会自动将这个sql片段我们要使用的sql中
。具体使用代码如下:
<sql id="allColumn">
id,username,password,gender,age,phone,delete_flag,create_time,update_time
</sql>
<select id="selectUser" resultType="com.example.demo.UserInfo">
select
<include refid="allColumn"></include>
from userinfo
</select>
然后我们来测试一下:
可以发现sql标签里定义的sql片段已经成功被拼接到sql里了。
七、在注解里使用动态sql
前面我们都是在xml文件里使用的动态sql,那么在注解里可以使用吗?答案是可以的,在注解里使用动态sql,只需要在编写的sql放到一个<script>标签里即可,例如我们将前面使用<if>标签的动态sql放到注解里使用,具体代码示例如下:
@Insert("<script>"+
" insert into userinfo\n" +
" <trim prefix=\"(\" suffix=\")\" prefixOverrides=\",\" suffixOverrides=\",\" >\n" +
" <if test=\"username != null\">username,</if>\n" +
" <if test=\"password != null\">password,</if>\n" +
" <if test=\"gender != null\">gender,</if>\n" +
" <if test=\"phone != null\">phone,</if>\n" +
" <if test=\"age != null\">age,</if></trim>\n" +
" values\n" +
" <trim prefix=\"(\" suffix=\")\" prefixOverrides=\",\" suffixOverrides=\",\" >\n" +
" <if test=\"username != null\">#{username},</if>\n" +
" <if test=\"password != null\">#{password},</if>\n" +
" <if test=\"gender != null\">#{gender},</if>\n" +
" <if test=\"phone != null\">#{phone},</if>\n" +
" <if test=\"age != null\">#{age},</if></trim>"+
"</script>")
public int addUser(UserInfo userInfo);
测试一下:
可以发现if标签也生效了。
事实上,一般不推荐在注解里使用动态sql,其一是不好看,毕竟谁都不想这么一大段代码出现在自己的代码里,其二是容易出错,由于整个sql都是写在双引号里的,还需要出来处理转义字符的问题,这个一不小心就会导致代码出现问题,因此要写动态sql的话还是建议在xml文件里写。