SSM框架开发web项目连串(四) MyBatis之神速控制动态SQL

  maven工程协会如下图

  图片 1

  完整示例

  上边就是动态SQL的顺序要素的主导内容,熟稔之后会让大家编辑SQL时更是便于和灵活,上面给出完整代码示例供参考。

  小结 

  以上即为MyBatis动态SQL的内容,在测试类中可以各类尝试改变各类输入值,来查看效果,文中即使各类成分都事关到了,不过多少地点还留存欠缺,并未过多少深度入增添,例如最终的foreach,大家的参数不必然是单个,而且也不必然是集结,那几个情况大家都该怎么处理,按自身的内需再去深切学习和询问,往往很快会有深刻映像。一个标题与措施的次第难题,当遭逢标题后,顺着难题去找办法之后,往往很好记住。反之,不成难点和利用场景,单纯的学习方法和理论意义应该会逊色一些。最终关键仍然把那么些基础的事物搞懂,再去渐渐延伸。

  if、set、trim篇

  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判断之后会吸引报错的逗号将不会存在,同样能够兑现相关职能。

  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);

}

  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>

  即可方便的兑现该现象。

  背景

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

图片 2

  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 GENDE福睿斯 =
‘男’和前面的<if>部分构成起来,通过动态SQL提供的<if>标签给语句预加一层判断,test属性值为布尔类型,true或许false,当为true(即真)时,才会把<if>标签下的内容添加到语句中一呼百应为值,那里的test中即判断输入参数中岁数是还是不是为空,不为空则添加【and AGE = #{age}】到【select * from person where GENDETiggo =
‘男’】后边,为空则不加,那样就高达了并且满足二种要求,但只定义了一个方式和一条SQL。

  前言

       
通过前边的MyBatis部分学习,已经得以运用MyBatis独立打造一个数据库程序,基本的增删查改/关联查询等等都足以兑现了。简单的单表操作和涉及查询在其实开的业务流程中毫无疑问会有,但是大概只会占一部分,很多业务必要往往夹杂着一些急需大家在后台去看清的参数,举个例子,大家基本都上过购物网站,想要查看心仪的货品列表,可以由此货品分类筛选,也可以通过货品价位来筛选,还足以同时依照分类和价格来筛选,那里我们得以简不难单的知道为经过货品归类和货物价位的筛选分别为select语句中where前边的2个子句,类似category=XXX和price
> xxx and price
<xxx,具体怎么筛选要看用户怎么操作。假如根据事先的门路,大家要分别定义多少个select方法和sql语句,这几个就关乎到了一个静态动态的题材,用户的操作、输入等等都以不确定的,即动态的,不过大家事先在sql映射文件中写的语句都是本着单个操作单个想法去写死的,即静态的。那样一来,随着需要和判断的的四处增大,这些代码量会很可怕。其它一个难题,假设我们有选择Java代码拼接过复杂SQL语句经历,应该不会感觉到很便宜,本身使用hibernate的时候也拼接过HQL,共同点就是那几个分隔符、空格之类的写起来很劳苦,也简单出错。MyBatis提供了动态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
,如故会出错,同时更新操作也不会一蹴而就了。

  1.更新语句中的if

  前面都以询问,大家换个立异摸索,那里更新大家只想翻新部分字段,而且要基于参数是还是不是为空来确定是还是不是更新,那里以姓名和性别为例。

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

  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>

  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也不会现出了。

  if、where、trim篇

  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>同样的效能。

  总览

       
MyBatis提供的动态SQL成分实际就是通过在我们的sql语句中放到标签完毕动态,具体标签如下图所示。

       图片 3

       
纯熟jsp、jstl、el表明式那套的,应该对其中大多数标签名都不生疏,也正如易于精晓,具体用法上边分别开展剖析。为了整合具体的采纳境况,将方面成分细分为四组来演示,分别为【if、where、trim】、【if、set、trim】、【choose、when、otherwise】、【foreach】

  foreach篇

  for循环大家应该都不生疏,这里的foreach同样关键用以迭代集合,那么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。

  实体类(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 + "]";
    }

}

  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>

  最终测试

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);
        }

    }
}
网站地图xml地图