Mybatis动态SQL

一:动态SQL语句

动态SQL可以说是Mybatis的一大特点。在使用过JDBC来写SQL语句,你应该能理解不同的条件有不同的SQL语句要拼接,往往一个字符串被东拼西凑,特别痛苦,而且还得保证拼接的时候2段SQL片段之间要保留空格等待,利用动态SQL可以保证彻底摆脱这种痛苦!

  其实使用动态SQL也不是一件容易的事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。

  如果有之前在学web的时候接触过JSTL或者任何基于类XML语言的文本处理器,,或许你对动态SQL有一定的似曾相识感觉,在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。

  Mybatis中用于实现动态SQL元素主要有if、choose、trim、where、set、foreach

这里我们快速准备一下简单的小框架吧!

1:if标签

动态 SQL 通常要做的事情是有条件地包含 where 子句的一部分。简单说传来的值用if判断,有的话就拼接到where后面。

    <!--根据性别和年龄查询-->
    <!--注意:必须要带一个where 1=1 否则sql语句少了where语句,,if判断某个值为空就不会拼接某个片段 -->
    <select id="findByAgeAndSex" parameterType="student" resultMap="studentMapper">
        select * from student where 1=1
        <if test="age!=0">
            and sage=#{age}
        </if>
        <if test="sex!=null and sex!=''">
            and ssex=#{sex}
        </if>
    </select>

2:choose、when、otherwise标签

这3个标签是一个整体和JSTL的一样,它们的本质都有点像java的switch分支语句,还是按照上面的例子,假设我传来年龄就按照年龄查询,传来性别就按照性别查询,年龄和性别都传来,就按照标签判断的先后顺序选择一个靠前的,然后下一个判断将不在执行,直接跳出,如果都不传则执行otherwise标签

<!--根据性别和年龄的其中一个查询-->
    <select id="findByAgeAndSexChoose" parameterType="student" resultMap="studentMapper">
        <!--基本sql语句-->
        select * from student where 1=1
        <!--switch开始-->
        <choose>
            <!--case :-->
            <when test="age!=0">
                and sage=#{age}
            </when>
            <!--case :-->
            <when test="sex!=null and sex!=''">
                and ssex=#{sex}
            </when>
            <!--default 如果都不成立则执行下面查询5条数据-->
            <otherwise>
                limit 5
            </otherwise>
        </choose>
    </select>

3:where、set、trim标签

先说一下where,其实大家有没有发现,我前2个示例都有where 1=1,这是干嘛用的呢?其实这个是一个恒等式,加where 1=1和不加都一样,但是加上了,后面的拼接语句就可以使用 and xx=xx and xxx=xxx 如果没加,那么后面的if判断成立就会形成一个select * from student  where and sage=xx;大家肯定发现错误了,其实Mybatis帮我们解决了where 1=1的拼接问题,我们可以不用自己手动写where属性了,我就改造一下第一个例子

<!--根据性别和年龄查询-->
    <!--加上where标签后就不用写恒等式了,就连前面的and也可写可不写 看下面的2个if里面-->
    <select id="findByAgeAndSex" parameterType="student" resultMap="studentMapper">
        select * from student
        <where>
            <if test="age!=0">
                 sage=#{age}
            </if>
            <if test="sex!=null and sex!=''">
                and ssex=#{sex}
            </if>
        </where>
    </select>

现在我们来聊聊trim,这个东西第一眼看上去特别难理解,以至于我都不知道是啥玩意,但是明白以后还是感觉不错的,就是用的很少,先不废话直接上代码看看

<!--
    使用trim标签完成where案例
    trim标签有4个属性:
    prefix:前缀覆盖并增加其内容。也就是给中的sql语句加上前缀;
    suffix:后缀覆盖并增加其内容。给包裹的sql语句加上后缀;
    prefixOverrides:前缀判断的条件。取消指定的前缀,如where;
    suffixOverrides:后缀判断的条件。取消指定的后缀,如"and |or "逗号等。
    -->
    <select id="findByAgeAndSex" parameterType="student" resultMap="studentMapper">
        select * from student
        <trim prefix="where" prefixOverrides="or |and ">
            <if test="age!=0">
                and sage=#{age}
            </if>
            <if test="sex!=null">
                and ssex=#{sex}
            </if>
        </trim>
    </select>
    <!--
        prefix代表前缀,它包裹着2个if标签,假设2个if都成立则语句是这样的
        select * from student where and sage=#{age} and ssex=#{sex};
        这样的语句是不是有问题呢?仔细一看 where后面有个and,没错因为if判断成功,
        就会拼接一个sql片段 and 也被拼接上了,但是别着急
        prefixOverrides上场,这个代表前缀重写,prefixOverrides="and |or ",凡是前缀为
        and或者or的全部重写,那重新成什么呢?别多想 说白了就是把匹配上的前缀删除了
        所以我们再总结一下 :
        select * from student SQL语句
        prefix="where" 开始添加前缀
        where and sage=#{age} and ssex=#{sex}
        prefixOverrides="and |or "开始前缀重写 就是去除where后全部语句最前面匹配重写
        where sage=#{age} and ssex=#{sex}
        相对于的后缀和后缀重写也是一样的,只不过在后面
        
        注意:"and▢|or▢"必须要有空格 否则匹配不上
    -->

聊完trim我们就来解决最后一个set了,这个玩意比trim容易,虽然trim难点,但是它可以写出set和where的功能,现在我来介绍一下set

<!--更新学生姓名  地址-->
    <!--这个set标签的内部可以放更新的字段 可以自动去除尾部的逗号,-->
    <update id="update" parameterType="student">
        update student
        <set>
             <if test="name!=null and name!=''">sname=#{name},</if>
             <if test="address!=null and address!=''">saddress=#{address},</if>
        </set>
        where sid=#{id}
    </update>
    <!--
        其实trim也可以完成对上面的操作
         update student
        <trim prefix="set" suffixOverides=",">
             <if test="name!=null and name!=''">sname=#{name},</if>
             <if test="address!=null and address!=''">saddress=#{address},</if>
        </trim>
        where sid=#{id}
    -->

4:foreach标签

  动态SQL的另一种常见的使用场景就是对集合进行遍历(尤其是遍历in条件语句的内部),在这我来给大家介绍一个mybatis的foreach循环集合标签,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符,你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。

<!--查询包含的id-->
    <!--
        open:整个循环内容开头的字符串。
        close:整个循环内容结尾的字符串。
        separator:每次循环的分隔符。
        item:从迭代对象中取出的每一个值。
        index:如果参数为集合或者数组,该值为当前索引值,如果参数为Map类型时,该值为Map的key。
        collection:要迭代循环的属性名。
           List<Student> findContionId(List<Integer> ids);这个是我接口的名称
           大家好奇为什么collection值是list而不上ids呢?在这里就有明确的答案引用自别处博客-->
    <select id="findContionId" parameterType="Integer" resultMap="studentMapper">
        select * from student
        <where>
            <foreach collection="list" item="x" open="sid in (" close=")" separator=",">
                #{x}
            </foreach>
        </where>
    </select>

5:SQL片段

虽然SQL片段不属于动态SQL里面的,但是我认为和动态SQL这一章节将比较合适,那什么是SQL片段呢?大家肯定用过<jsp:include="xx" />这个动作元素吧,其实SQL片段和这个差不多,都是把一个SQL片段封装起来,后期谁用谁调用这个片段就行了

<!--SQL片段定义-->
    <sql id="sqlid">
        select * from student
    </sql>
    <!--查询单个-->
    <select id="findById" resultMap="studentMapper">
        <!--调用SQL片段 通过id-->
        <include refid="sqlid"></include>
         where sid=#{id}
    </select>

结语:今天带大家了解了一下mybatis的动态sql,在接下来的一篇文章来为大家介绍一下mybatis的多表操作,和后期的注解开发希望大家多多支持,希望我那文章对你有一点点帮助,如有意见或者不同观点,希望您可以通过评论或者私信交流谢谢

原文地址:https://www.cnblogs.com/antLaddie/p/12779000.html