MyBatis(三)

时间:2024-04-09 17:14:43

本篇主要介绍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文件里写。