太实用了😋,MyBatis动态标签

2,657 阅读6分钟

这是我参与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动态标签的详细解释,如果有错误的地方,还请留言指正,如果觉得本文对你有帮助那就点个赞👍吧😋😻😍

默认标题_动态分割线_2021-07-15-0.gif