MyBatis学习-4

Dynamic SQL

Posted by lvyonghao on April 17, 2019

MyBatis学习-4

  • if
  • choose(when,otherwise)
  • trim(where,set)
  • foreach
  • sql

上面这些就是我们的动态SQL语句了,他们能够非常方便的组合SQL语句,提高开发人员的效率。


1.if

我们可以再MyBatis的Mapper当中写SQL的时候通过if标签来判断是否在SQL语句中添加某个条件比如我们先写一个通过ID和LastName的模糊搜索:

select * from tbl_employee
    <if test="id!=null">
        id = #{id}
    </if>
    and and last_name like #{Lastname}   

如果我们的id传入为null,那么我们就只剩下模糊查询了,那怎么办呢,这时候就该我们的where标签了。


2.where

先来段代码解决一下上面的问题

        select * from tbl_employee
        <where>
            <if test="id!=null">
                id = #{id}
            </if>
            <if test="Lastname!=null and Lastname!=&quot;&quot;">
                and last_name like #{Lastname}
            </if>
        </where>

的确,从表面上来看,就是多了个where标签而已, 不过实质上, mybatis是对它做了处理,如果标签返回的内容是以AND 或OR 开头的,它会剔除掉第一个多出来的and或者是or。


3.trim

使用tirm你可以自己定义sql语句我先说几个他的属性:

  • prefix=“”在语句添加前缀
  • prefixOverrides=“”前缀覆盖,去掉整个字符串前面多余的字符
  • suffix=“”在语句中添加后缀
  • suffixOverrides=“”后缀覆盖,去掉整个字符串后面多余的字符串

下面写一个小小的测试:

先新建一个EmployeeMapperDyamicSQL接口吧

package com.snake_lvyonghao.MyBatis.Dao;

import com.snake_lvyonghao.MyBatis.bean.Employee;

import java.util.List;

public interface EmployeeMapperDyamicSQL {
    List<Employee> getEmpsByConditionIF(Employee employee);

    List<Employee> getEmpsByConditionTrim(Employee employee);
}

再来一个EmployeeMapperDyamicSQL.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.snake_lvyonghao.MyBatis.Dao.EmployeeMapperDyamicSQL">
    <!--查询员工,要求携带了哪个字段就带上这个字段的值-->
    <select id="getEmpsByConditionIF" resultType="com.snake_lvyonghao.MyBatis.bean.Employee">
        select * from tbl_employee
        <where>
            <if test="id!=null">
                id = #{id}
            </if>

            <if test="Lastname!=null and Lastname!=&quot;&quot;">
                and last_name like #{Lastname}
            </if>

            <if  test="email!=null and email.trim()!=&quot;&quot;">
                and email=#{email}
            </if>

            <if test="gender==0 or gender==1">
                and gender = #{gender}
            </if>
        </where>
    </select>

    <!--Tirm-->
    <select id="getEmpsByConditionTrim" resultType="com.snake_lvyonghao.MyBatis.bean.Employee">
        select * from tbl_employee
        <trim prefix="where" suffixOverrides="and" prefixOverrides="and">
            <if test="id!=null">
                id = #{id}
            </if>

            <if test="Lastname!=null and Lastname!=&quot;&quot;">
                and last_name like #{Lastname}
            </if>

            <if  test="email!=null and email.trim()!=&quot;&quot;">
                and email=#{email}
            </if>

            <if test="gender==0 or gender==1">
                and gender = #{gender}
            </if>

        </trim>
    </select>
</mapper>

最后放上我们的测试内容:

    @Test
    public void test07() throws IOException{
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();

        SqlSession openSession = sqlSessionFactory.openSession();

        try {
            EmployeeMapperDyamicSQL mapper = openSession.getMapper(EmployeeMapperDyamicSQL.class);
            Employee employee = new Employee(3,"%h%","huwenhao@lookout.com",null);
//            List<Employee> emps = mapper.getEmpsByConditionIF(employee);
//            for(Employee emp : emps){
//                System.out.println(emp);
//            }

            List<Employee> emps2 = mapper.getEmpsByConditionTrim(employee);
            for(Employee emp : emps2){
                System.out.println(emp);
            }
        }finally {
            openSession.close();
        }
    }

3.choose

它类似我们的带了break的switch-caes,同样我们先学习两个在choose标签中的的标签

  • when标签:就是咱的switch的意思,标签当中的内容自然是咱要执行的内容。
  • otherwhen标签:就是当咱所有的when都失败了则之行otherwhen标签中的内容

好的我就先做一个简单的测试,我们按照ID,LastName,email,gender的顺序查找: 首先在接口种生命一个新的方法List<Employee> getEmpsByConditionChoose(Employee employee);

然后写上我们的Mapper的配置

    <select id="getEmpsByConditionChoose" resultType="com.snake_lvyonghao.MyBatis.bean.Employee">
        select * from tbl_employee
        <where>
            <!--带了那个就用哪个查-->
            <choose>
                <when test="id!=null">
                    id = #{id}
                </when>
                <when test="Lastname!=null">
                    last_name like #{Lastname}
                </when>
                <when test="email!=null">
                    email = #{email}
                </when>
                <otherwise>
                    gender = 0
                </otherwise>
            </choose>
        </where>
    </select>

最后当然是我们的测试喽:

    @Test
    public void test07() throws IOException{
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();

        SqlSession openSession = sqlSessionFactory.openSession();

        try {
            EmployeeMapperDyamicSQL mapper = openSession.getMapper(EmployeeMapperDyamicSQL.class);
            Employee employee = new Employee(null,null,null,null);                 System.out.println(emp);

            List<Employee> emps3 = mapper.getEmpsByConditionChoose(employee);
            for(Employee emp : emps3){
                System.out.println(emp);
            }
        }finally {
            openSession.close();
        }
    }

当然为了测试我们选择在最初的时候把employee初始化参数都为null,怎么测试就看你了。


4.set

set这个在sql中我们通常用来做update操作,但是如果我们想想要在set中添加if语句我们该怎么做,这时候我们就要用到我们的set标签了

同样我们先在接口中声明一个方法List<Employee> getEmpsByConditionForeach(Integer id); 接下来去我们的Mapper中配置一番,我们根据给定的参数,并配合ID,修改传入不为null参数值的列。

    <update id="updateEmp">
        update tbl_employee
            <set>
                <if test="Lastname!=null">
                    last_name = #{Lastname},
                </if>
                <if test="email!=null">
                    email = #{email},
                </if>
                <if test="gender!=null">
                    gender = #{gender},
                </if>
            </set>
            <where>
                id = #{id}
            </where>
    </update>

在写一个测试run一下看看:

        try {
            EmployeeMapperDyamicSQL mapper = openSession.getMapper(EmployeeMapperDyamicSQL.class);
            Employee employee = new Employee(5,"lvyong","snake_lvyonghao@163.com","1");
            mapper.updateEmp(employee);
            openSession.commit();

5.foreach

foreach类似我们程序设计语言当中的for:each,在学习之前我们先来看看他的两个属性有什么作用:

  • collection:指定要遍历的集合(List类型的参数会被封装在Map当中,Map的key就叫list)
  • item:将当前遍历出的元素赋值给指定的元素
  • #{变量名}:就是取出item里变量的值,也就是当前遍历出的元素
  • separator:元素和元素之间的分隔符
  • open:以什么开始,�遍历所有的结果拼接一个开始的字符
  • close:以什么结束,遍历所有的结果拼接一个结束的字符
  • index:遍历list是index就是索引,item就是当前的值,遍历Map的时候index表示的就是map的key,item就是map的值

好我们先来在接口中写一个方法List<Employee> getEmpsByConditionForeach(List<Integer> list);。 然后在Mapper中来学习一下如何使用上面的属性吧,我希望能够根据Id去查询,并把结果封装到一个List当中去:

    <select id="getEmpsByConditionForeach" resultType="com.snake_lvyonghao.MyBatis.bean.Employee">
        SELECT * from tbl_employee
        <foreach collection="list" item="item_id" separator="," open="where id in(" close=")">
            #{item_id}
        </foreach>
    </select>

最后我们在测试类中它他进行测试:

    @Test
    public void test07() throws IOException{
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();

        SqlSession openSession = sqlSessionFactory.openSession();

        try {
            EmployeeMapperDyamicSQL mapper = openSession.getMapper(EmployeeMapperDyamicSQL.class);
            Employee employee = new Employee(5,"lvyong","snake_lvyonghao@163.com","1");
            List<Employee> emps4 = mapper.getEmpsByConditionForeach(Arrays.asList(1,2,3,4));
            for (Employee emp : emps4){
                System.out.println(emp);
            }
        openSession.commit();
        }finally {
            openSession.close();
        }
    }

批量操作用foreach真是太方便了,我还写了一个批量增加的,这里我就只放上一个Mapper的代码,具体的代码通过Github上的项目来看吧:

    <insert id="addEmps">
        insert into tbl_employee(last_name,email,gender,d_id)
        <foreach collection="emps" item="emp" separator="," open="VALUES">
            (#{emp.Lastname},#{emp.email},#{emp.gender},#{emp.department.id})
        </foreach>
    </insert>

6.sql && include

类似程序设计语言中的宏定义,sql抽取可重用的sql片段动态SQL语句也是可以的,include引用sql片段,还可以自定义一些property,sql标签内部就能使用自定义的属性${},我来简单的举个例子:

<sql id="insertColumn">
    id,last_name,email,${test}
</sql>
<!--引用的时候-->
<inlucde refid="insertColumn">
    <property name="test" value="abc"/>
</include>

7.其他参数

这里我们再介绍两个额外的参数:

  • _parameter:代表整个参数,如果是单个参数就代表这个参数,如果是多个参数就会封装成一个Map,代表这个Map
  • _databaseId:如果在数据库的配置文件中配置了detabaseIdProvider标签,就代表当前数据库的别名,通常用动态的SQL中的if语句判断当前数据库类型,然后执行不同的SQL语句

SSM源码地址