Mybatis【13】-- Mybatis动态Sql标签的使用

mybatis有一个强大的特性,其余框架在拼接sql的时候要特别谨慎,好比哪里须要空格,还要注意去掉列表最后一个列名的逗号,mybtis的动态sql能够帮助咱们逃离这样的痛苦挣扎,那就是动态SQL.它还能够处理一种状况,当你不肯定你的参数不知道是否是为空的时候,咱们不须要在业务逻辑中判断,直接在sql中处理,代码无比简洁。主要的动态sql标签以下:
java

  • <if></if>
  • <where></where>(trim,set)
  • <choose></choose>(when, otherwise)
  • <foreach></foreach>

注意事项:
在mapper中若是出现大于号(>),小于号(),大于等于号(),小于等于号()等,最好须要转换成为实体符号,这是由于mapper是XML文件,xml文件自己就含有较多的<>这样的尖括号,因此解析的时候可能会解析出错。sql

原符号 < <= > >= & ' "
替换符号 &lt; &lt;= &gt; &gt;= &amp; &apos; &quot;

<if>

咱们常常须要根据where后面的条件筛选出须要的数据,当多个条件拼接的时候,咱们通常使用<if></if>,若是if里面的条件成立,那么就会使用标签的语句,可是咱们能够知道where句子第一个标签是没有and的,然后面的条件都须要and,因此有一种作法是第一个使用where 1 = 1,这个条件恒成立,后面的全部子语句都加上and,若是增长判断,那么咱们只须要加<if>标签就能够了。数组

<!-- 动态sql if标签-->
    <!-- &可使用and来代替 ,注意!=须要连在一块儿写-->
    <select id="selectStudentByDynamicSQL" resultType="Student">
        <!--最经常使用的(动态参数) select id,name,age,score from student where name like '%' #{name} '%' -->
        <!-- 下面的是字符串拼接 ,只能写value,了解便可,容易sql注入,执行效率低,不建议使用-->
        select id,name,age,score
        from student
        where 1=1
        <if test="name != null and name != ''">
            and name like '%' #{name} '%'
        </if>
        <if test="age > 0">
            and age > #{age}
        </if>
    </select>

当有两个查询条件的时候,sql语句是:select * from student where 1=1 and name like '%' ? '%' and age > ?

当有一个查询条件的时候:sql语句就变成:select * from student where 1=1 and name like '%' ? '%'

当没有查询条件的时候,sql语句是:
select * from student where 1=1

<if></if>标签须要手动在where后面添加1=1语句,这是由于若是<if>后面的条件都是false的时候,where后面若是没有1=1语句,sql就剩下一个空空的where,sql就会报错。因此在where后面须要加上永真句子1=1,可是这样有一个问题,当数据量比较大的时候,会严重影响sql的查询效率。mybatis

<where></where>,<trim></trim>,<set></set>

使用<where></where>标签,在有查询语句的时候,自动补上where子句,在没有查询条件的时候,不会加上where子句,这也就解决了咱们上面所涉及到的问题,剩下的就是<if>标签的and子句,第一个,<if>片断里面能够不包含and,也能够包含,系统会自动去掉and,可是其余的<if>片断里面的and,必须写上,不然会出错。下面的写法中,若是name为null,第二个if标签中的if也会被去掉,不会报错。app

<select id="selectStudentByDynamicSQLWhere" resultType="Student">
        <!--最经常使用的(动态参数) select id,name,age,score from student where name like '%' #{name} '%' -->
        <!-- 下面的是字符串拼接 ,只能写value,了解便可,容易sql注入,执行效率低,不建议使用-->
        select id,name,age,score
        from student
        <where>
            <if test="name != null and name != ''">
                and name like '%' #{name} '%'
            </if>
            <if test="age > 0">
                and age > #{age}
            </if>
        </where>
    </select>

若是where里面是不规范的,那咱们能够经过 来自定义where元素的功能, 标签主要有如下属性: 框架

  • prefix:在包含的内容前加上前缀,不是百分之百会加,会根据须要自动加
  • suffix:在包含的内容后面加上后缀,不是百分之百会加,会根据须要自动加
  • prefixOverrides:能够把包含内容的首部某些内容忽略(不能本身增长),不必定会忽略,根据须要自动忽略
  • suffixOverrides:也能够把包含内容的尾部的某些内容忽略(不能本身增长),同上

下面这样的是错误的,当传入的name不为空,并且age大于0的时候ide

<select id="selectStudentByDynamicSQLWhere" resultType="Student">
        select id,name,age,score
        from student
        <trim prefix="where" prefixOverrides="and">
            <if test="name != null and name != ''">
                name like '%' #{name} '%'
            </if>
            <if test="age > 0">
                age > #{age}
            </if>
        </trim>
    </select>

不会本身增长and在第二个age前面:



下面的是正确的,咱们在两个<if>标签前面都增长了and,第二个and会自动去掉:code

<select id="selectStudentByDynamicSQLWhere" resultType="Student">
        select id,name,age,score
        from student
        <trim prefix="where" prefixOverrides="and">
            <if test="name != null and name != ''">
                and name like '%' #{name} '%'
            </if>
            <if test="age > 0">
                and age > #{age}
            </if>
        </trim>
    </select>

下面是后缀模式, prefix="set"表示在整个语句前面加上前缀set, suffixoverride=","表示每个语句后面的后缀","能够被忽略,若是是须要的话suffix=" where id = #{id}表示在整个语句后面增长where id = #{id},:xml

update user
<trim prefix="set" suffixoverride="," suffix=" where id = #{id} ">
  <if test="name != null and name.length()>0"> name=#{name} , </if>
  <if test="age != null "> age=#{age} ,  </if>
</trim>

固然,咱们对上面的语句还有动态解决的方案,那就是 标签: 对象

<update id="updateStudent">
		update student
		<set>
            <!-- 第一个if标签的逗号必定要有,最后一个标签的逗号能够没有-->
            <if test="name != null"> name=#{name},</if>
            <if test="age != null">age=#{age},</if>
            <if test="score != null"> score=#{score},</if>
        </set>
         where id=#{id}
	</update>

<choose>, <when>, <otherwise>

有时候,咱们只想去匹配第一个条件,或者第一个条件不匹配的时候才会去匹配第二个条件,不像<where></where>标签里面的<if></if>同样会去判断全部的子语句是否能够匹配,而是遇到一个匹配的就会执行跳出<choose></choose>

<!-- 	selectStudentByDynamicSQLChoose 相似于switch,知足后就不会判断后面的了-->
    <!-- 若是名字不为空,那么按照名字来查询,若是名字为空,就按照年龄来查询,若是没有查询条件,就没有查询条件 -->
    <select id="selectStudentByDynamicSQLChoose" resultType="Student">
        <!--最经常使用的(动态参数) select id,name,age,score from student where name like '%' #{name} '%' -->
        select id,name,age,score
        from student
        <where>
            <choose>
                <when test="name != null and name != ''">
                    and name like '%' #{name} '%'
                </when>
                <when test="age > 0">
                    and age > #{age}
                </when>
                <otherwise>
                    and 1 != 1
                </otherwise>
            </choose>
        </where>
    </select>

<choose>标签就像是switch语句,每个<when>都像是case,后面默认跟上break语句,只要知足一个就不会判断后面的子语句了,当前面全部的<when></when>都不执行的时候,就会执行<otherwise></otherwise>标签的内容,这个内容也就像是switch语句里面的default。

foreach

动态SQL要有一个比较多的操做是对一个集合进行遍历,一般是在构建IN条件语句的时候。须要注意的点:

  • collection 表示须要遍历的集合类型,array表示须要遍历的数组
  • open,close,separator是对遍历内容的SQL拼接
  • foreach 元素的功能很是强大,它容许你指定一个集合,声明能够在元素体内使用的集合项(item)和索引(index)变量。它也容许你指定开头与结尾的字符串以及在迭代结果之间放置分隔符。
  • 你能够将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象传递给 foreach 做为集合参数。当使用可迭代对象或者数组时,index 是当前迭代的次数,item 的值是本次迭代获取的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。

1.好比咱们须要查找学生的id为1,2,3的学生信息,咱们不但愿分开一次査一个,而是但愿将数组id一次传进去,查出来一个学生的集合。

sql接口能够这样写,传入一个对象的数组:

public List<Student>selectStudentByDynamicSQLForeachArray(Object[]studentIds);

sql语句以下,遍历array数组的时候,指定左边符号是左括号,右边是右括号,元素以逗号分隔开:

<!-- select * from student where id in (1,3) -->
    <select id="selectStudentByDynamicSQLForeachArray" resultType="Student">
        select id,name,age,score
        from student
        <if test="array !=null and array.length > 0 ">
            where id in
            <foreach collection="array" open="(" close=")" item="myid" separator=",">
                #{myid}
            </foreach>
        </if>
    </select>

2.当遍历的是一个类型为int的list列表时:

public List<Student>selectStudentByDynamicSQLForeachList(List<Integer>studentIds);

sql语句以下,colleaction指定为list:

<select id="selectStudentByDynamicSQLForeachList" resultType="Student">
        select id,name,age,score
        from student
        <if test="list !=null and list.size > 0 ">
            where id in
            <foreach collection="list" open="(" close=")" item="myid" separator=",">
                #{myid}
            </foreach>
        </if>
    </select>

3.当遍历的是一个类型为对象的list:

public List<Student>selectStudentByDynamicSQLForeachListStudent(List<Student>students);

sql语句里面与上面类似,只是在使用属性的时候不太同样:

<select id="selectStudentByDynamicSQLForeachListStudent" resultType="Student">
        select id,name,age,score
        from student
        <if test="list !=null and list.size > 0 ">
            where id in
            <foreach collection="list" open="(" close=")" item="stu" separator=",">
                #{stu.id}
            </foreach>
        </if>
    </select>

<sql></sql>

用于定义sql片断,方便在其余SQL标签里面复用,在其余地方复用的时候须要使用<include></include>子标签,<sql>能够定义sql的任何部分,因此<include>标签能够放在动态SQL的任何位置。

<sql id="selectHead">
		select id,name,age,score
		 from student
	</sql>
    <!-- 可读性比较差 -->
    <select id="selectStudentByDynamicSQLfragment" resultType="Student">
        <include refid="selectHead"></include>
        <if test="list !=null and list.size > 0 ">
            where id in
            <foreach collection="list" open="(" close=")" item="stu" separator=",">
                #{stu.id}
            </foreach>
        </if>
    </select>

动态sql让SQL写起来更加简洁,减小了不少重复代码,动态sql之间能够相互拼接,只要符合sql语句规范便可。

【做者简介】
秦怀,公众号【秦怀杂货店】做者,技术之路不在一时,山高水长,纵使缓慢,驰而不息。这个世界但愿一切都很快,更快,可是我但愿本身能走好每一步,写好每一篇文章,期待和大家一块儿交流。

相关文章
相关标签/搜索