Mybatis小结之动态sql

Posted tanyunlong_nice

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybatis小结之动态sql相关的知识,希望对你有一定的参考价值。

什么是动态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的所有学生信息。

注意一下,能用”<![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语句将是:

这将导致查询失败。即使只满足一个查询条件还是有问题,比如满足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不插入。


以上是关于Mybatis小结之动态sql的主要内容,如果未能解决你的问题,请参考以下文章

Mybatis之通用mapper使用注解的方式写动态sql-小结

MyBatis-05-笔记

MyBatis框架动态SQL

SQL mybatis动态查询小结

MyBatis动态SQL小结

mybatis动态sql之bind标签