zoukankan      html  css  js  c++  java
  • mybatis 动态sql语句(2)

    什么是动态SQL
    
    MyBatis的一个强大特性之一通常是它的动态SQL能力。如果你有使用JDBC或其他相似框架的经验,你就明白条件串联SQL字符串在一起是多么地痛苦,确保不能忘了空格或者在列表的最后的省略逗号,动态SQL可以彻底处理这种痛苦。
    
    通常使用动态SQL不可能是独立的一部分,MyBatis当然使用一种强大的动态SQL语言来改进这种情形,这种语言可以被用在任意映射的SQL语句中。
    
    动态SQL元素和使用JSTL或其它相似的基于XML的文本处理器相似,在MyBatis之前的版本中,有很多元素需要了解,MyBatis3大大地提升了它们,现在用不到原先一半的元素就能工作了,MyBatis采用功能强大的基于OGNL的表达式来消除其他元素。
    
    OK,介绍就到这儿,下面来进入动态SQL的学习吧。
    
    if
    
    在动态SQL中所做的最通用的事情就是包含部分where子句的条件,比如:
    
    <select id="selectInCondition" parameterType="student" resultType="student">
        select * from student where studentId > #{studentId}
        <if test="studentName != null">
            and studentName = #{studentName};
        </if>
    </select>
    
    具体实现不写了,那么如果我这么调用:
    
    List<Student> list = StudentOperator.getInstance().selectInCondition(0, "Jack", 0, null);
    
    查询的就是studentId>0且studentName=”Jack”的所有学生信息,如果换一种调用方式:
    
    List<Student> list = StudentOperator.getInstance().selectInCondition(0, null, 0, null);
    
    那么查询的就是studentId>0的所有学生信息。
    
    多个where子句也是一样的,比如:
    
    <select id="selectInCondition" parameterType="student" resultType="student">
        <![CDATA[
            select * from student where studentId > #{studentId}
        ]]>
        <if test="studentName != null and studentName != 'Jack' ">
            and studentName = #{studentName}
        </if>
        <if test="studentAge != 0">
            and studentAge = #{studentAge};
        </if>
    </select>
    
    注意一下,能用”<![CDATA[ ... ]]>”尽量还是用,不过只包动态SQL外的内容。
    
    另外,test里面可以判断字符串、整型、浮点型,大胆地写判断条件吧。如果属性是复合类型,则可以使用A.B的方式去获取复合类型中的属性来进行比较。
    
    choose、when、otherwise
    
    有时候我们不想应用所有的应用条件,相反我们想选择很多情况下的一种。和Java中的switch…case…类似,MyBasit提供choose元素。
    
    上面的例子是两种if判断都可能存在,接下来使用choose、when、other做一些修改:
    
    <select id="selectInCondition" parameterType="student" resultType="student">
        <![CDATA[
            select * from student where studentId > #{studentId}
        ]]>
        <choose>
            <when test="studentName != null">
                and studentName = #{studentName};
            </when>
            <when test="studentAge != 0">
                and studentAge = #{studentAge};
            </when>
            <otherwise>
                or 1 = 1;
            </otherwise>
        </choose>
    </select>
    
    两个when只能满足一个,都不满足则走other。还是注意一下这里的”<![CDATA[ ... ]]>”,不可以包围整个语句。
    
    trim、where、set
    
    第一个例子已经示例了if的用法,但是这种用法有个缺陷—-动态SQL外必须有where子句。
    
    什么意思,因为很多时候我们需要where后面的子句都动态生成,而不是事先有一个where,这样就有问题,比如说:
    
    <select id="selectInCondition" parameterType="student" resultType="student">
        <![CDATA[
            select * from student where
        ]]>
        <if test="studentName != null and studentName != 'Jack' ">
            and studentName = #{studentName}
        </if>
        <if test="studentAge != 0">
            and studentAge = #{studentAge};
        </if>
    </select>
    
    如果所有条件都不匹配,那么生成的SQL语句将是:
    
    select * from student where
    
    这将导致查询失败。即使只满足一个查询条件还是有问题,比如满足studentName那个吧,生成的SQL语句将是:
    
    select * from student where and studentName = #{studentName};
    
    这个查询也会失败。
    
    解决办法也有,一个讨巧的办法是用where 1 = 1的方式,即:
    
    <select id="selectInCondition" parameterType="student" resultType="student">
        <![CDATA[
            select * from student where 1 = 1
        ]]>
        <if test="studentName != null and studentName != 'Jack' ">
            and studentName = #{studentName}
        </if>
        <if test="studentAge != 0">
            and studentAge = #{studentAge};
        </if>
    </select>
    
    因为”1 = 1″永远满足,所以相当于给where加了一层true而已,此时动态SQL生成什么where判断条件就是什么。
    
    另外一个解决办法是利用MyBatis中的一个简单处理方式,这在90%情况下都会有用而且。而在不能使用的地方,可以以自定义方式处理。加上一个简单的改变,所有的事情都会顺利进行:
    
    <select id="selectInCondition" parameterType="student" resultType="student">
        <![CDATA[
            select * from student
        ]]>
        <where>
            <if test="studentName != null and studentName != 'Jack' ">
                and studentName = #{studentName}
            </if>
            <if test="studentAge != 0">
                and studentAge = #{studentAge};
            </if>
        </where>
    </select>
    
    where元素知道如果由被包含的标记返回任意内容,就仅仅插入where。而且,如果以”and”或”or”开头的内容,那么就会跳过where不插入。
    
    如果where元素没有做出你想要的,那么可以使用trim元素来自定义。比如,和where元素相等的trim元素是:
    
    <trim prefix="WHERE" prefixOverrides="AND |OR ">
    …
    </trim>
    
    即:
    
    <select id="selectInCondition" parameterType="student" resultType="student">
        select * from student
        <trim prefix="WHERE" prefixOverrides="AND |OR ">
            <if test="studentName != null and studentName != 'Jack' ">
                and studentName = #{studentName}
            </if>
            <if test="studentAge != 0">
                and studentAge = #{studentAge};
            </if>
        </trim>
    </select>
    
    特别要注意,prefixOverrides中的空白也是很重要的。
    
    最后一个小内容,和动态更新语句相似的解决方案是set。set元素可以被用于动态包含更新的列,而不包含不需要更新的。比如:
    
    <update id="updateStudentAgeById" parameterType="Student">
        <!--update student set studentAge = #{studentAge} where 
            studentId = #{studentId}; -->
        <![CDATA[
            update student
        ]]>
        <set>
            <if test="studentAge != 0">studentAge = #{studentAge}</if>
        </set>
        where studentId = #{studentId}
    </update>
    
    可以对比一下,注释掉的是原update语句,没有注释的是加入动态SQL之后的语句。
    
    这里,set元素会动态前置set关键字,而且也会消除任意无关的逗号。如果你对和这里对等的trim元素好奇,它看起来是这样的:
    
    <trim prefix="SET" prefixOverrides=",">
    …
    </trim>
    
    这种时候我们附加一个后缀,同时也附加一个前缀。
    
    foreach
    
    另外一个动态SQL通用的必要操作时迭代一个集合,通常是构建在in条件中的。比如(上面的例子都是我在自己电脑上跑通过的例子,这个例子就直接复制MyBatis官方文档上的内容了):
    
    <select id="selectPostIn" resultType="domain.blog.Post">
        <![CDATA[
            SELECT * FROM POST P WHERE ID in
        ]]>
        <foreach item="item" index="index" collection="list"
            open="(" separator="," close=")">
            #{item}
        </foreach>
    </select>
    
    foreach是非常强大的,它允许你指定一个集合,声明集合项和索引变量,它们可以用在元素体内。他也允许你指定开放和关闭字符串,在迭代之间放置分隔符。这个元素是很智能的,它不会偶然地附加多余的分隔符。
    

      

    什么是动态SQL

     

    MyBatis的一个强大特性之一通常是它的动态SQL能力。如果你有使用JDBC或其他相似框架的经验,你就明白条件串联SQL字符串在一起是多么地痛苦,确保不能忘了空格或者在列表的最后的省略逗号,动态SQL可以彻底处理这种痛苦。

     

    通常使用动态SQL不可能是独立的一部分,MyBatis当然使用一种强大的动态SQL语言来改进这种情形,这种语言可以被用在任意映射的SQL语句中。

     

    动态SQL元素和使用JSTL或其它相似的基于XML的文本处理器相似,在MyBatis之前的版本中,有很多元素需要了解,MyBatis3大大地提升了它们,现在用不到原先一半的元素就能工作了,MyBatis采用功能强大的基于OGNL的表达式来消除其他元素。

     

    OK,介绍就到这儿,下面来进入动态SQL的学习吧。

     

    if

     

    在动态SQL中所做的最通用的事情就是包含部分where子句的条件,比如:

     

    <select id="selectInCondition" parameterType="student" resultType="student">

        select * from student where studentId > #{studentId}

        <if test="studentName != null">

            and studentName = #{studentName};

        </if>

    </select>

     

    具体实现不写了,那么如果我这么调用:

     

    List<Student> list = StudentOperator.getInstance().selectInCondition(0, "Jack", 0, null);

     

    查询的就是studentId>0且studentName=”Jack”的所有学生信息,如果换一种调用方式:

     

    List<Student> list = StudentOperator.getInstance().selectInCondition(0, null, 0, null);

     

    那么查询的就是studentId>0的所有学生信息。

     

    多个where子句也是一样的,比如:

     

    <select id="selectInCondition" parameterType="student" resultType="student">

        <![CDATA[

            select * from student where studentId > #{studentId}

        ]]>

        <if test="studentName != null and studentName != 'Jack' ">

            and studentName = #{studentName}

        </if>

        <if test="studentAge != 0">

            and studentAge = #{studentAge};

        </if>

    </select>

     

    注意一下,能用”<![CDATA[ ... ]]>”尽量还是用,不过只包动态SQL外的内容。

     

    另外,test里面可以判断字符串、整型、浮点型,大胆地写判断条件吧。如果属性是复合类型,则可以使用A.B的方式去获取复合类型中的属性来进行比较。

     

    choose、when、otherwise

     

    有时候我们不想应用所有的应用条件,相反我们想选择很多情况下的一种。和Java中的switch…case…类似,MyBasit提供choose元素。

     

    上面的例子是两种if判断都可能存在,接下来使用choose、when、other做一些修改:

     

    <select id="selectInCondition" parameterType="student" resultType="student">

        <![CDATA[

            select * from student where studentId > #{studentId}

        ]]>

        <choose>

            <when test="studentName != null">

                and studentName = #{studentName};

            </when>

            <when test="studentAge != 0">

                and studentAge = #{studentAge};

            </when>

            <otherwise>

                or 1 = 1;

            </otherwise>

        </choose>

    </select>

     

    两个when只能满足一个,都不满足则走other。还是注意一下这里的”<![CDATA[ ... ]]>”,不可以包围整个语句。

     

    trim、where、set

     

    第一个例子已经示例了if的用法,但是这种用法有个缺陷—-动态SQL外必须有where子句。

     

    什么意思,因为很多时候我们需要where后面的子句都动态生成,而不是事先有一个where,这样就有问题,比如说:

     

    <select id="selectInCondition" parameterType="student" resultType="student">

        <![CDATA[

            select * from student where

        ]]>

        <if test="studentName != null and studentName != 'Jack' ">

            and studentName = #{studentName}

        </if>

        <if test="studentAge != 0">

            and studentAge = #{studentAge};

        </if>

    </select>

     

    如果所有条件都不匹配,那么生成的SQL语句将是:

     

    select * from student where

     

    这将导致查询失败。即使只满足一个查询条件还是有问题,比如满足studentName那个吧,生成的SQL语句将是:

     

    select * from student where and studentName = #{studentName};

     

    这个查询也会失败。

     

    解决办法也有,一个讨巧的办法是用where 1 = 1的方式,即:

     

    <select id="selectInCondition" parameterType="student" resultType="student">

        <![CDATA[

            select * from student where 1 = 1

        ]]>

        <if test="studentName != null and studentName != 'Jack' ">

            and studentName = #{studentName}

        </if>

        <if test="studentAge != 0">

            and studentAge = #{studentAge};

        </if>

    </select>

     

    因为”1 = 1″永远满足,所以相当于给where加了一层true而已,此时动态SQL生成什么where判断条件就是什么。

     

    另外一个解决办法是利用MyBatis中的一个简单处理方式,这在90%情况下都会有用而且。而在不能使用的地方,可以以自定义方式处理。加上一个简单的改变,所有的事情都会顺利进行:

     

    <select id="selectInCondition" parameterType="student" resultType="student">

        <![CDATA[

            select * from student

        ]]>

        <where>

            <if test="studentName != null and studentName != 'Jack' ">

                and studentName = #{studentName}

            </if>

            <if test="studentAge != 0">

                and studentAge = #{studentAge};

            </if>

        </where>

    </select>

     

    where元素知道如果由被包含的标记返回任意内容,就仅仅插入where。而且,如果以”and”或”or”开头的内容,那么就会跳过where不插入。

     

    如果where元素没有做出你想要的,那么可以使用trim元素来自定义。比如,和where元素相等的trim元素是:

     

    <trim prefix="WHERE" prefixOverrides="AND |OR ">

    </trim>

     

    即:

     

    <select id="selectInCondition" parameterType="student" resultType="student">

        select * from student

        <trim prefix="WHERE" prefixOverrides="AND |OR ">

            <if test="studentName != null and studentName != 'Jack' ">

                and studentName = #{studentName}

            </if>

            <if test="studentAge != 0">

                and studentAge = #{studentAge};

            </if>

        </trim>

    </select>

     

    特别要注意,prefixOverrides中的空白也是很重要的。

     

    最后一个小内容,和动态更新语句相似的解决方案是set。set元素可以被用于动态包含更新的列,而不包含不需要更新的。比如:

     

    <update id="updateStudentAgeById" parameterType="Student">

        <!--update student set studentAge = #{studentAge} where 

            studentId = #{studentId}; -->

        <![CDATA[

            update student

        ]]>

        <set>

            <if test="studentAge != 0">studentAge = #{studentAge}</if>

        </set>

        where studentId = #{studentId}

    </update>

     

    可以对比一下,注释掉的是原update语句,没有注释的是加入动态SQL之后的语句。

     

    这里,set元素会动态前置set关键字,而且也会消除任意无关的逗号。如果你对和这里对等的trim元素好奇,它看起来是这样的:

     

    <trim prefix="SET" prefixOverrides=",">

    </trim>

     

    这种时候我们附加一个后缀,同时也附加一个前缀。

     

    foreach

     

    另外一个动态SQL通用的必要操作时迭代一个集合,通常是构建在in条件中的。比如(上面的例子都是我在自己电脑上跑通过的例子,这个例子就直接复制MyBatis官方文档上的内容了):

     

    <select id="selectPostIn" resultType="domain.blog.Post">

        <![CDATA[

            SELECT * FROM POST P WHERE ID in

        ]]>

        <foreach item="item" index="index" collection="list"

            open="(" separator="," close=")">

            #{item}

        </foreach>

    </select>

     

    foreach是非常强大的,它允许你指定一个集合,声明集合项和索引变量,它们可以用在元素体内。他也允许你指定开放和关闭字符串,在迭代之间放置分隔符。这个元素是很智能的,它不会偶然地附加多余的分隔符。

  • 相关阅读:
    Golang语言编程规范
    关于redis的几件小事(三)redis的数据类型与使用场景
    关于redis的几件小事(二)redis线程模型
    关于redis的几件小事(一)redis的使用目的与问题
    关于MQ的几件小事(七)如果让你设计一个MQ,你怎么设计
    关于MQ的几件小事(六)消息积压在消息队列里怎么办
    关于MQ的几件小事(五)如何保证消息按顺序执行
    关于MQ的几件小事(四)如何保证消息不丢失
    关于MQ的几件小事(三)如何保证消息不重复消费
    关于MQ的几件小事(二)如何保证消息队列的高可用
  • 原文地址:https://www.cnblogs.com/ipetergo/p/6752250.html
Copyright © 2011-2022 走看看