MyBatis使用动态SQL标签的小陷阱,MyBatis之快速掌握

  以往MyBatis愈来愈受我们的垂怜了,它的优势大家都精通,小编就少之甚少说了,直接说注重。

何以是动态SQL

  前言

        通过前边的MyBatis部分学习,已经能够动用MyBatis独立创设一个数据库程序,基本的增加和删除查改/关联合检查询等等都落实了。简单的单表操作和涉嫌查询在实质上开的业务流程中自然会有,不过大概只会占一部分,相当多事情须求往往夹杂着一些内需大家在后台去看清的参数,比如,大家基本都上过购物网址,想要查看心仪的商品列表,能够经过货色归类筛选,也足以透过商品价位来筛选,还足以同期依附分类和价格来筛选,这里我们能够省略的掌握为通过货物归类和商品价位的筛选分别为select语句中where前边的2个子句,类似category=XXX和price > xxx and price <xxx,具体怎么筛选要看客户怎么操作。即使依照事先的门道,我们要分头定义多个select方法和sql语句,这么些就涉嫌到了一个静态动态的标题,顾客的操作、输入等等都以不鲜明的,即动态的,但是我们事先在sql映射文件中写的语句都是针对单个操作单个主张去写死的,即静态的。那样一来,随着须求和判别的的无休止增大,那些代码量会很吓人。此外四个主题材料,若是我们有使用Java代码拼接过复杂SQL语句经历,应该不会倍感很有益于,本人使用hibernate的时候也拼接过HQL,共同点正是那一个分隔符、空格之类的写起来很辛勤,也便于失误。MyBatis提供了动态SQL这一特色,能同有时间改良上述三种开辟境况。

  MyBatis中提供动态SQL功用,大家能够动用<if><when><where><otherwise><foreach>等等,那样我们就能够写出依据标准变化的动态SQL了,可是,在那中间,大家日常应用的<if>标签有二个小误区,一非常大心就能够掉下去,下边先举个常规的事例:

MyBatis的四个精锐天性之一日常是它的动态SQL技巧。即使您有采用JDBC或任何平时框架的阅历,你就领会条件串联SQL字符串在共同是何等地痛楚,确定保证无法忘了空格或然在列表的终极的简短逗号,动态SQL能够通透到底管理这种伤痛。

  总览

        MyBatis提供的动态SQL元素实际就是通过在大家的sql语句中放置标签完结动态,具体标签如下图所示。

       图片 1

        领会jsp、jstl、el表明式这套的,应该对当中山大学部分标具名都不素不相识,也正如便于精晓,具体用法上边分别举办剖析。为了整合现实的接纳景况,将上边成分细分为四组来演示,分别为【if、where、trim】、【if、set、trim】、【choose、when、otherwise】、【foreach】

<select id="findActiveBlogWithTitleLike" 
     parameterType="Blog" resultType="Blog">
  SELECT * FROM BLOG 
  WHERE state = ‘ACTIVE’ 
  <if test="title != null">
    AND title like #{title}
  </if>
</select>

常常来说使用动态SQL不只怕是独自的一局地,MyBatis当然使用一种强盛的动态SQL语言来改进这种意况,这种语言能够被用在大肆映射的SQL语句中。

  背景

private Integer id;         //主键
private String name;        //姓名
private String gender;      //性别
private Integer age;        //年龄
private String ifIT;        //是否从事IT行业

图片 2

  在地点的例证中,当title不等于null时,<if>标签中间的规范才会被拼接上,那样,SQL语句就是动态的了。

动态SQL成分和选用JSTL或另外相似的依附XML的公文管理器相似,在MyBatis以前的版本中,有相当多因素必要精通,MyBatis3大环球进步了它们,未来用不到原本二分一的要素就能够干活了,MyBatis选拔功效强盛的基于OGNL的表达式来清除其余因素。

  if、where、trim篇

  但是,当大家对富有条件实行决断期,你是还是不是会那样写:

OK,介绍就到此时,上面来步入动态SQL的上学呢。

  1.查询语句中的if

  以上为大家定义的一人的习性,数据库中也会有一位的数据表。未来假诺须求查询人中的全体男子,同偶尔候要是输入参数不惑之年龄不为空,就依据性别和年龄查询。在平素不应用动态SQL以前,依照大家的惯有思路,大家必要在Mapper接口中定义四个查询格局,同期分别对应在SQL映射文件中定义五个<select>语句,如下:

<select id="selectPerson1" parameterType="psn" resultMap="personResultMap">
    select * from person where GENDER  = '男'
</select>

<select id="selectPerson2" parameterType="psn" resultMap="personResultMap">
    select * from person where GENDER  = '男' and AGE = #{age}
</select>

  那样一来,随着类似的内需更增加,大家的章程和SQL语句量会增到比比较多,並且会开采,其实语句中留存非常多种复部分。那么有未有措施能同一时间应对近似的连锁要求,同期收缩代码量呢?动态SQL就提供了有关的功效完毕那些必要,比如上述场景,大家就能够只需定义一个措施,对应的SQL语句写成如下:

<select id="selectPerson" parameterType="psn" resultMap="personResultMap">
    select * from person where GENDER  = '男'
        <if test="age != null">
            and AGE = #{age}
        </if>
</select>

  在这里项<select>我们将规定的(静态的的有个别)select * from person where GENDEPRADO = '男'和前边的<if>部分组成起来,通过动态SQL提供的<if>标签给语句预加一层判别,test属性值为布尔类型,true大概false,当为true(即真)时,才会把<if>标签下的剧情加多到语句中一呼百应该为值,这里的test中即推断输入参数中岁数是不是为空,不为空则增添【and AGE = #{age}】到【select * from person where GENDE奥迪Q3 = '男'】前边,为空则不加,那样就高达了还要满意两种供给,但只定义了三个艺术和一条SQL。

<select id="findActiveBlogWithTitleLike" 
     parameterType="Blog" resultType="Blog">
  SELECT * FROM BLOG 
  WHERE
  <if test="userId != null">
     state = ‘ACTIVE’ 
  </if>

  <if test="title != null">
    AND title like #{title}
  </if>
</select>

 

  2.查询语句中if的where革新

  进一步扩充要是想把where前面包车型客车局地都动态化,这里以性别为例,查询时假使参数中有不为空的性别值,则基于性别查询,反之则查询全数,有了前方if的就学,大家轻松写出如下动态SQL:

<select id="selectPerson1" parameterType="psn" resultMap="personResultMap">
    select * from person where
        <if test="gender != null">
            gender = #{gender}
        </if>
</select>

 

  那时候难题来了,当性别不为空时,语句是 select * from person where gender = #{gender} ,那样还是能健康查询出咱们想要的结果,可是假如性别为空,会发觉语句产生了 select * from person where ,那眼看是生成三个漏洞百出的SQL了,为了缓慢解决类似的主题素材,动态SQL<where>能帮大家缓慢解决那么些标题,我们得以将上述语句优化成如下:

<select id="selectPerson1" parameterType="psn" resultMap="personResultMap">
    select * from person
    <where>
        <if test="gender != null">
            gender = #{gender}
        </if>
    </where>
</select>

  这样mybatis在这里处会依赖<where>标签中是或不是有内容来规定要不要丰硕where,在这里边运用<where>后,假使年龄为空,则前边引发错误的where也不会出现了。

  没难题吗?最少语法上正确的,最少它能够健康生成多少个SQL。

if

  3.指向性where的trim同等转变

  进一步扩张,倘使大家查询有四个参数须求推断,依据性别和年龄参数,有了前头<if>和<where>的打听,大家就足以写出如下SQL:

<select id="selectPerson2" parameterType="psn" resultMap="personResultMap">
    select * from person
    <where>
        <if test="gender != null">
            gender = #{gender}
        </if>
        <if test="age != null">
            and age = #{age}
        </if>
    <where>
</select>

  乍一看基本没什么毛病了,在这里间【性别空、年龄空】、【性别不空、年龄不空】、【性别不空、年龄空】都没难点,不过要是是【性别空、年龄不为空】,按理来说语句形成这样 select * from person where and age = #{age} ,然后一旦您入手尝试一下,就能够发掘,并不会,那也反映了<where>多少个精锐之处,它不但会依据成分中内容是或不是为空决定要不要增添where,还有恐怕会活动过滤掉内容底部的and只怕or,别的层空间格之类的难点也会智能管理。

  MyBatis还提供了一种更加灵活的<trim>标签,在这里间能够代表<where>,如下面的概念能够修改成如下,同样能够完成效果与利益:

<select id="selectPerson2" parameterType="psn" resultMap="personResultMap">
    select * from person
    <trim prefix="where" prefixOverrides="and |or " >
        <if test="gender != null">
            and gender = #{gender}
        </if>
        <if test="age != null">
            and age = #{age}
        </if>
    </trim>
</select>

  <trim>标签共有六特性格,分别为【prefix】、【prefixOverrides】、【suffix】、【suffixOverrides】,prefix代表会给<trim>标签中内容丰裕的前缀,当然前提是内容不为空,prefixOverrides代表前缀过滤,过滤的是内容的前缀,suffix和suffixOverrides则分级对应后缀。举个例子地点的口舌中一经性别和年龄都不为空,<trim>会在加多where前缀的还要,把第三个<if>中的and去掉,那样来兑现<where>一样的效应。

  可是,不明了你注意到了没,当有着规范都为null的时候,会冒出哪些动静?

在动态SQL中所做的最通用的政工就是含有部分where子句的标准,举例:

  if、set、trim篇

SELECT * FROM BLOG 
  WHERE
<select id="selectInCondition" parameterType="student" resultType="student">
    select * from student where studentId > #{studentId}
    <if test="studentName != null">
        and studentName = #{studentName};
    </if>
</select>

  1.立异语句中的if

  前边都以查询,我们换个立异探究,这里更新大家只想翻新部分字段,并且要依靠参数是还是不是为空来分明是还是不是更新,这里以人名和性别为例。

<update id="updatePerson">
    update person set
    <if test="name != null">
        NAME = #{name},
    </if>
    <if test="gender != null">
        GENDER = #{gender}
    </if>
</update>

  见到了啊?这样的SQL能打响举行么?

具体达成不写了,那么一旦本人那样调用:

  2.更新语句中if的set立异

  这里假诺【姓别为空】或许【性别和性别都为空】,类似事先的where难题同样也来了,所以MyBatis同样也提供了<set>标签来消除这一难题,所以地点的概念能够优化成如下所示

<update id="updatePerson1">
    update person
    <set>
     <if test="name != null">
            NAME = #{name},
        </if>
        <if test="gender != null">
            GENDER = #{gender},
        </if>
    </set>
</update>

   在那地,<set>会依附标签中剧情的有无来分明要不要增添set,同有的时候间能活动回复内容后缀逗号,可是有少数要注意,不一样于<where>,当<where>中内容为空时,大家得以摸清全部人的新闻,可是此间更新语句中,<set>内容为空时,语句产生 update person ,还是会出错,同期创新操作也不会立见成效了。

  答案当然是NO。

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

  3.针对set的trim同等调换

  在此以前介绍到的<trim>灵活之处,在那通过改变属性值,也能用来代表<set>,上边的定义使用<trim>改写如下所示:

<update id="updatePerson2">
    update person
    <trim prefix="set" suffixOverrides=",">
        <if test="name != null">
            NAME = #{name},
        </if>
        <if test="gender != null">
            GENDER = #{gender}
        </if>
    </trim>
</update>

  这里安装前缀为set,后缀过滤为逗号“,”,那样一来,在if决断之后会掀起报错的逗号将不会存在,一样可以兑现相关职能。

  那么该如何是好?那将要记住了,当您写动态SQL时候,先思量一下会不会发生负有法则都不树立的图景,会不会油然则生唯有三个WHERE而尚未原则的情状,那么您要做的就是加八个<where>标签将持有条件包起来。

查询的正是studentId>0且studentName="Jack"的持有学员音信,固然换一种调用方式:

  choose、when、otherwise篇

  后边大家询问到的,<select>查询语句中where前面,<if>通过推断各样参数是不是为空来分明是还是不是加多其子句内容到where前面,是一个增添的关联,不过只要我们的要求,不是加上,而是多选一,比如姓名(name)、性别(gender)、是不是从事It行当(ifIT),具体来说就是,即使优先推断姓名是还是不是有值,有的话就依靠姓名查,未有的话其次再剖断性别是或不是有值,有的话就依据性别查,也尚未的话就依靠是或不是从事IT行当来查。那样一来,依据后面理解到的<if><where>就好像不怎么头大,不仅唯有多种判定,还关乎到二个事先级前后相继难点,一下子就好像很难火速想到三个轻巧方便的门道。MyBatis同样提供了一套<choose>、<when>、<otherwise>来帮大家化解类似上边的难点。

  假若以为不太好回想,能够联想Java中标准判别的switch,switch对应这里的<choose>,case对应<when>,一旦某些case条件满意了会break跳出,同期假诺都不满意,最终还应该有个default能够对应这里的<otherwise>,所以最终<when>和<otherwise>中有且独有八个会满意,也就独有一项内容会被增添进去。根据上面的必要,我们得以写出如下动态SQL:

<select id="selectPersonExt" parameterType="psn" resultMap="personResultMap">
    select * from person
    <where>
        <choose>
            <when test="name!=null">
                NAME = #{name}
            </when>
            <when test="gender!=null">
                GENDER = #{gender}
            </when>
            <otherwise>
                IF_IT = #{ifIT}
            </otherwise>
        </choose>
    </where>
</select>

  就能够方便的兑现该地方。

<select id="findActiveBlogWithTitleLike" 
     parameterType="Blog" resultType="Blog">
  SELECT * FROM BLOG 
 <where>
  <if test="userId != null">
     state = ‘ACTIVE’ 
  </if>

  <if test="title != null">
    AND title like #{title}
  </if>
 </where>
</select>
List<Student> list = StudentOperator.getInstance().selectInCondition(0, null, 0, null);

  foreach篇

  for循环我们应该都不目生,这里的foreach同样任重(英文名:rèn zhòng)而道远用以迭代集结,那么SQL中哪些地点会用到会集呢,用过in的应有相比熟谙,例如下边select语句:

select * from person where age in(10,20,30,40)

  上边语句能够查询出年龄为10或20或30或40的人,最近几年纪多少是多个集结,但是通过参数字传送入的会集是动态的,我们不恐怕预感数值和像这样写死,MyBatis提供的<foreach>就可以兑现该意义。该集同盟为参数字传送入,以上气象方法定义和SQL语句能够写成如下所示:

List<Person> selectForeachAge(List<Integer> ageList);

<select id="selectForeachAge" resultMap="personResultMap">
    select * from person where age in
    <foreach collection="list" item="age" index="i" open="(" close=")" separator=",">
        #{age}
    </foreach>
</select>

   这里我们得以看来,<foreach>共有6个属性。

  item:表示群集迭代时元素的外号,这里对应#{age}中的age

  index:集合迭代时索引,用于表示集结此时迭代到的职位

  open、close、separator:那多个分别表示早先、甘休、分隔符,在此边,我们用过in语句询问时应该都明白,使用到集中的查询语句结构首要部分能够描述如下所示: SELECT column_name(s) FROM table_name WHERE column_name IN (value1,value2,...) 。能够看出在IN关键字的末尾,集结内容两边分别是左括号、右括号,中间集结的顺序要素之间用逗号隔开分离,正好与这里的多个属性分别对应。

  collection:这本性子是须求的,在此边我们传入的是单个参数即三个List,所以属性值正是list。

  那样,当全体法则都不树立即,WHERE也不会被拼上。

那么查询的正是studentId>0的有所学生音信。

  完整示例

  上边正是动态SQL的各类要素的为主内容,熟知之后会让大家编辑SQL时更是有益和灵活,下边给出完整代码示例供参谋。

  

三个where子句也是平等的,比如:

  maven工程结构如下图

  图片 3

  那时,有机灵的同伴开掘了,如若第贰个标准不成立,第三个构建,那SQL会不会成为那样?

 

  MyBatis配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 这里可以定义类的别名,在mapper.xml文件中应用会方便很多 -->
    <typeAliases>
        <typeAlias alias="psn" type="com.mmm.pojo.Person" />
    </typeAliases>
    <!-- 环境配置 -->
    <environments default="envir">
        <environment id="envir">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://192.168.0.100:3306/ssm?characterEncoding=utf-8"/>
                <property name="username" value="root"/>
                <property name="password" value="abc123"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/mmm/mapper/personMapper.xml"/>
    </mappers>
</configuration>
 SELECT * FROM BLOG 
     WHERE
    AND title like #{title}
<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>

  实体类(Person)

package com.mmm.pojo;

public class Person {
    private Integer id;            //主键
    private String name;        //姓名
    private String gender;        //性别
    private Integer age;        //年龄
    private String ifIT;        //是否从事IT行业

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getGender() {
        return gender;
    }
    public void setGender(String gender) {
        this.gender = gender;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public String getIfIT() {
        return ifIT;
    }
    public void setIfIT(String ifIT) {
        this.ifIT = ifIT;
    }
    @Override
    public String toString() {
        return "Person [id="   id   ", name="   name   ", gender="   gender
                  ", age="   age   ", ifIT="   ifIT   "]";
    }

}

  这一个就放心好了,当你用<if>标签包围条件后,它会自动去掉AND的。

 

  Mapper接口(PersonMapper)

package com.mmm.mapper;

import java.util.List;

import com.mmm.pojo.Person;

public interface PersonMapper {

    //查找所有Person对象,返回集合类型,用于在测试类中查看动态SQL结果
    List<Person> selectAll();

    //用于测试查询语句中if、where、trim
    List<Person> selectPerson(Person p);
    List<Person> selectPerson1(Person p);
    List<Person> selectPerson2(Person p);

    //用于测试更新语句中if、set、trim
    void updatePerson(Person p);
    void updatePerson1(Person p);
    void updatePerson2(Person p);

    //用于测试choose、where、otherwise
    List<Person> selectPersonExt(Person p);

    //用于测试foreach
    List<Person> selectForeachAge(List<Integer> ageList);

}

 

当心一下,能用"<![CDATA[ ... ]]>"尽量照旧用,可是只包动态SQL外的内容。

  SQL映射文件(personMapper.xml)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.mmm.mapper.PersonMapper">
    <resultMap type="psn" id="personResultMap">
        <id column="ID" property="id" />
        <result column="NAME" property="name" />
        <result column="GENDER" property="gender" />
        <result column="AGE" property="age" />
        <result column="IF_IT" property="ifIT" />
    </resultMap>

    <select id="selectAll" resultMap="personResultMap">
        select * from person
    </select>


    <!-- 针对查询语句中if -->
    <select id="selectPerson" parameterType="psn" resultMap="personResultMap">
        select * from person where GENDER  = '男'
            <if test="age != null">
                and AGE = #{age}
            </if>
    </select>

    <!-- 针对where -->
    <select id="selectPerson1" parameterType="psn" resultMap="personResultMap">
        select * from person
        <where>
            <if test="gender != null">
                gender = #{gender}
            </if>
        </where>
    </select>

    <!-- 针对where的 trim转换 -->
    <select id="selectPerson2" parameterType="psn" resultMap="personResultMap">
        select * from person
        <trim prefix="where" prefixOverrides="and |or " >
            <if test="gender != null">
                and gender = #{gender}
            </if>
            <if test="age != null">
                and age = #{age}
            </if>
        </trim>
        <trim prefix="" prefixOverrides="" suffix="" suffixOverrides=""></trim>
    </select>


    <!-- 针对更新语句中if -->
    <update id="updatePerson">
        update person set
        <if test="name != null">
            NAME = #{name},
        </if>
        <if test="gender != null">
            GENDER = #{gender}
        </if>
        where ID = #{id}
    </update>

    <!-- 针对set -->
    <update id="updatePerson1">
        update person
        <set>
            <if test="name != null">
                NAME = #{name},
            </if>
            <if test="gender != null">
                GENDER = #{gender}
            </if>
        </set>
    </update>

    <!-- 针对set的trim转换 -->
    <update id="updatePerson2">
        update person
        <trim prefix="set" suffixOverrides=",">
            <if test="name != null">
                NAME = #{name},
            </if>
            <if test="gender != null">
                GENDER = #{gender}
            </if>
        </trim>
    </update>

    <!-- choose when otherwise -->
    <select id="selectPersonExt" parameterType="psn" resultMap="personResultMap">
        select * from person
        <where>
            <choose>
                <when test="name!=null">
                    NAME = #{name}
                </when>
                <when test="gender!=null">
                    GENDER = #{gender}
                </when>
                <otherwise>
                    IF_IT = #{ifIT}
                </otherwise>
            </choose>
        </where>
    </select>

    <!-- foreach -->
    <select id="selectForeachAge" resultMap="personResultMap">
        select * from person where age in
        <foreach collection="list" item="age" index="i" open="(" close=")" separator=",">
            #{age}
        </foreach>
    </select>

</mapper>

另外,test里面能够确定字符串、整型、浮点型,大胆地写判别标准吧。若是属性是复合类型,则足以选用A.B的议程去取得复合类型中的属性来扩充相比较。

  最终测量检验

package com.mmm.test;

import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import com.mmm.mapper.PersonMapper;
import com.mmm.pojo.Person;

public class TestDB {

    static PersonMapper mapper;

    static {
        //直接实例SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //MyBatis配置文件路径
        String path = "mybatis-config.xml";
        //通过路径获取输入流
        Reader reader = null;
        try {
            reader = Resources.getResourceAsReader(path);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //通过reader构建sessionFactory
        SqlSessionFactory sessionFactory = builder.build(reader);
        //获取SqlSession对象
        SqlSession sqlSession = sessionFactory.openSession();
        //获取Mapper实例
        mapper = sqlSession.getMapper(PersonMapper.class);
    }

    @Test
    public void testSelect() throws Exception {
        Person p = new Person();
        //p.setAge(11);
        //p.setGender("男");
        List<Person> list = mapper.selectPerson2(p);
        for(Person psn:list) {
            System.out.println(psn);
        }
    }

    @Test
    public void testUpdate() throws Exception {
        Person p = new Person();
        p.setId(10001);
        //p.setName("小改2");
        //p.setGender("男");
        mapper.updatePerson2(p);
        List<Person> list = mapper.selectAll();
        for(Person psn:list) {
            System.out.println(psn);
        }

    }

    @Test
    public void testSelectExt() throws Exception {
        Person p1 = new Person();
        //p1.setName("小红");
        //p.setGender("男");
        p1.setIfIT("是");
        List<Person> list = mapper.selectPersonExt(p1);
        for(Person psn:list) {
            System.out.println(psn);
        }

    }

    @Test
    public void testSelectForeachAge() throws Exception {
        List<Integer> ageList = new ArrayList<Integer>();
        ageList.add(21);
        ageList.add(25);
        ageList.add(36);
        List<Person> list = mapper.selectForeachAge(ageList);
        for(Person psn:list) {
            System.out.println(psn);
        }

    }
}

 

  小结 

  以上即为MyBatis动态SQL的内容,在测验类中能够各类尝试改造各样输入值,来查看效果,文中即便各种成分都关系到了,可是有些地方还存在不足,并没有过多少深度入扩张,比如最后的foreach,大家的参数不自然是单个,並且也不确定是汇集,这一个处境大家都该怎么管理,按自身的急需再去深刻学习和精晓,往往比极快会有深远影象。二个难题与方式的顺序难点,当遭遇难点后,顺着难点去找办法之后,往往很好记住。反之,未有失常态和接纳场景,单纯的就学方法和谈论意义应该会比不上一些。最后关键还是把那么些基础的东西搞懂,再去逐步延伸。

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中的二个轻易易行管理格局,这在70%情形下都会有用何况。而在不可能运用的地点,能够以自定义方式管理。加上叁个简约的改变,全体的政工都会顺遂进行:

<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是分外刚劲的,它同意你钦命八个汇集,评释群集项和目录变量,它们得以用在要素体内。他也同意你钦命开放和倒闭字符串,在迭代里面放置分隔符。这么些成分是很智能的,它不会一时地附增多余的分隔符。

本文由星彩网app下载发布于星彩彩票app下载,转载请注明出处:MyBatis使用动态SQL标签的小陷阱,MyBatis之快速掌握

TAG标签:
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。