Mybatis九(动态sql)

你离开我真会死。 提交于 2019-11-27 07:18:15

if标签

接口(EmployeeMapper.java)

package com.fish.dao;

import java.util.List;

import com.fish.pojo.Employee;

public interface EmployeeMapper {
    /**
     * 动态sql if拼接
     * @Author ZFH
     * @Date 2019年7月29日
     */
    public List<Employee> selEmployeeByConationIf(Employee employee);
}

配置文件(EmployeeMapper.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.fish.dao.EmployeeMapper">

    <select id="selEmployeeByConationIf" resultType="com.fish.pojo.Employee">
        select id, last_name lastName, email, gender from tbl_employee where
        <!--
            test:判断表达式(OGNL)
            OGNL参照官方文档
            test:
                从参数中取值判断
                对于特殊字符需要使用转义字符例如
                &&:&amp;&anm;或者and
                "":&quot;&quot 或者使用单引号
            OGNL会进行紫都城的转换判断 例如下面的gender是String类型 但是我可以直接写 gender==1
         -->
            <if test="id != null">
                id = #{id}
            </if>
            <if test="lastName != null and lastName !='' ">
                and last_name like  "%" #{lastName} "%"
            </if>
            <if test="email != null and email != '' ">
                and email = #{email}
            </if>
            <if test="gender == 0 or gender == 1">
                and gender = #{gender}
            </if>
    </select>
</mapper>

测试类

@org.junit.Test
public void test01() throws IOException {
    //读取配置文件
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    //获取SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession openSession = sqlSessionFactory.openSession();
    //调用getMapper方法获取该接口的实现类
    EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
    Employee employee = new Employee();
    employee.setId(1);
    employee.setLastName("2");
    List<Employee> selEmployeeByConationIf = mapper.selEmployeeByConationIf(employee);
    System.out.println(selEmployeeByConationIf);
    //关闭Session
    openSession.close();

}

运行结果

[Employee [id=1, lastName=222, email=ZFH_FISH@163.COM, gender=1]]

问题

有些同学可能发现问题了,如果id我不传只传lastName 那么mybatis进行sql拼接的时候会带上and,这样一来sql语句就会报错了,那么怎么解决呢,这里有两种方法,1:在动态sql之前的sql后面的where后面加上1=1 然后每一个条件都加上and,2:使用where标签

where标签

将上面的方法改造一下

接口(EmployeeMapper.xml)

<select id="selEmployeeByConationIf" resultType="com.fish.pojo.Employee">
    select id, last_name lastName, email, gender from tbl_employee 
    <where>
        <!--
            test:判断表达式(OGNL)
            OGNL参照官方文档
            test:
                从参数中取值判断
                对于特殊字符需要使用转义字符例如
                &&:&amp;&anm;或者and
                "":&quot;&quot 或者使用单引号
            OGNL会进行紫都城的转换判断 例如下面的gender是String类型 但是我可以直接写 gender==1
         -->
        <if test="id != null">
            id = #{id}
        </if>
        <if test="lastName != null and lastName !='' ">
            and last_name like  "%" #{lastName} "%"
        </if>
        <if test="email != null and email != '' ">
            and email = #{email}
        </if>
        <if test="gender == 0 or gender == 1">
            and gender = #{gender}
        </if>
    </where>
</select>

测试类

@org.junit.Test
public void test01() throws IOException {
    //读取配置文件
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    //获取SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession openSession = sqlSessionFactory.openSession();
    //调用getMapper方法获取该接口的实现类
    EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
    Employee employee = new Employee();
    //employee.setId(1);
    employee.setLastName("2");
    List<Employee> selEmployeeByConationIf = mapper.selEmployeeByConationIf(employee);
    System.out.println(selEmployeeByConationIf);
    //关闭Session
    openSession.close();

}

运行结果

[Employee [id=1, lastName=222, email=ZFH_FISH@163.COM, gender=1], Employee [id=2, lastName=2, email=2, gender=1], Employee [id=5, lastName=22, email=lisi@163.com, gender=0]]

完美解决,通过这个例子我们知道,where标签可以帮我们把第一个多余的and或or去掉

上面的问题虽然解决了,但是还有一个问题,如果我的and是现在每个条件的后面的例如这样

<if test="id != null">
            id = #{id} and
        </if>
        <if test="lastName != null and lastName !='' ">
            last_name like  "%" #{lastName} "%"
        </if>
        <if test="email != null and email != '' ">
            and email = #{email} and 
        </if>
        <if test="gender == 0 or gender == 1">
            gender = #{gender}
        </if>

那么sql又会报错了 这时候怎么解决呢 下面我们来介绍一下trim标签

trim(自定义字符串截取)

接口(EmployeeMapper.java)

/**
 * 动态sql trim
 * @Author ZFH
 * @Date 2019年7月29日
 */
public List<Employee> selEmployeeByConationTrim(Employee employee);

配置文件(EmployeeMapper.xml)

<select id="selEmployeeByConationTrim"
    resultType="com.fish.pojo.Employee">
    select id, last_name lastName, email, gender from tbl_employee
    <!-- trim:
        prefix="":为拼接完的sql加一个前缀
        prefixOverrides="":前缀覆盖,去掉整个字符串前面多余的字符串
        suffix="" :为整个字符串加一个后缀
        suffixOverrides="":后缀覆盖,去掉整个字符串后面多余的字符串
     -->
    <trim prefix="where" suffixOverrides="and">
        <if test="id != null">
            id = #{id} and
        </if>
        <if test="lastName != null and lastName !='' ">
            last_name like "%" #{lastName} "%" and
        </if>
        <if test="email != null and email != '' ">
            and email = #{email} and
        </if>
        <if test="gender == 0 or gender == 1">
            gender = #{gender}
        </if>
    </trim>
</select>

测试类

@org.junit.Test
public void test02() throws IOException {
    //读取配置文件
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    //获取SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession openSession = sqlSessionFactory.openSession();
    //调用getMapper方法获取该接口的实现类
    EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
    Employee employee = new Employee();
    //employee.setId(1);
    employee.setLastName("2");
    List<Employee> selEmployeeByConationIf = mapper.selEmployeeByConationTrim(employee);
    System.out.println(selEmployeeByConationIf);
    //关闭Session
    openSession.close();

}

运行结果

[Employee [id=1, lastName=222, email=ZFH_FISH@163.COM, gender=1], Employee [id=2, lastName=2, email=2, gender=1], Employee [id=5, lastName=22, email=lisi@163.com, gender=0]]

再一次完美解决

choole分支选择

接口(EmployeeMapper.java)

/** 
* 动态sql choose分支选择 
* @Author ZFH 
* @Date 2019年7月29日 
*/ 
public List selEmployeeByConationChoose(Employee employee);

配置文件(EmployeeMapper.xml)

<select id="selEmployeeByConationChoose"
    resultType="com.fish.pojo.Employee">
    select id, last_name lastName, email, gender from tbl_employee
    <where>
        <choose>
            <when test="id != null and id != '' ">
                id = #{id}
            </when>
            <when test="lastName != null and lastName != '' ">
                and last_name = #{lastName}
            </when>
            <when test="email != null and email != '' ">
                and email = #{email}
            </when>
            <otherwise>
                and gender = 0
            </otherwise>
        </choose>
    </where>
</select>

测试类

@org.junit.Test
public void test03() throws IOException {
    //读取配置文件
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    //获取SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession openSession = sqlSessionFactory.openSession();
    //调用getMapper方法获取该接口的实现类
    EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
    Employee employee = new Employee();
    employee.setId(1);
    employee.setLastName("2");
    List<Employee> selEmployeeByConationIf = mapper.selEmployeeByConationChoose(employee);
    System.out.println(selEmployeeByConationIf);
    //关闭Session
    openSession.close();

}

运行结果

[Employee [id=1, lastName=222, email=ZFH_FISH@163.COM, gender=1]]

if与choose的区别

很多同学发现if与choose的效果一样,那为什么这两个都存在呢,其实这两个标签效果是不一样的,if标签是只要满足条件的都会拼接到sql上,而choose标签是只要有一个满足了条件,则只会拼接这一条,其他的都不执行了.

set(修改信息)

接口(EmployeeMapper.java)

public void selEmployeeByConationSet2(Employee employee);

配置文件(EmployeeMapper.xml)

<select id="selEmployeeByConationSet2"
    resultType="com.fish.pojo.Employee">
    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}
</select>

测试类

@org.junit.Test
public void test04() throws IOException {
    //读取配置文件
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    //获取SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession openSession = sqlSessionFactory.openSession();
    //调用getMapper方法获取该接口的实现类
    EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
    Employee employee = new Employee();
    employee.setId(1);
    employee.setLastName("张三1");
    mapper.selEmployeeByConationSet2(employee);

    openSession.commit();
    //关闭Session
    openSession.close();

}

使用trim完成修改

配置文件(其他的都一样)

<select id="selEmployeeByConationSet"
    resultType="com.fish.pojo.Employee">
    update tbl_employee 
        <trim prefix="set" suffixOverrides=",">
            <if test="lastName != null">
                last_name = #{lastName},
            </if>
            <if test="email != null">
                email = #{email},
            </if>
            <if test="gender != null">
                gender = #{gender}
            </if>
        </trim>
    where id = #{id}
</select>

使用foreach遍历集合

接口(EmployeeMapper.java)

/**
 * 动态sql foreach
 * @Author ZFH
 * @Date 2019年7月29日
 */
public List<Employee> selEmployeeByConationForeach(List<Integer> ids);

配置文件(EmployeeMapper.xml)

<select id="selEmployeeByConationForeach"
    resultType="com.fish.pojo.Employee">
    select * from tbl_employee where id in 
    <!-- 
        collection:指定要遍历的集合,有三个取值分别是:array,list,collection分别对应了数组,集合,Map根据传入值的类型设置
        item:将当前遍历出的元素赋值给指定的变量
        separator:每个元素之间的分隔符
        open:拼接一个开始的字符串
        close:拼接一个结束的字符串
        index:索引.遍历list的时候index就是索引,item就是当前值
                  遍历map的时候,index是map的key,item是map的值
     -->
        <foreach collection="list" item="item_id" separator="," open="(" close=")" index="i">
            #{item_id}
        </foreach>
</select>

测试类

@org.junit.Test
public void test05() throws IOException {
    //读取配置文件
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    //获取SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession openSession = sqlSessionFactory.openSession();
    //调用getMapper方法获取该接口的实现类
    EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
    List<Integer> list = new ArrayList<Integer>();
    list.add(1);
    list.add(2);
    List<Employee> selEmployeeByConationForeach = mapper.selEmployeeByConationForeach(Arrays.asList(1,2,3));

    System.out.println(selEmployeeByConationForeach);

    //关闭Session
    openSession.close();

}

运行结果

[Employee [id=1, lastName=张三1, email=ZFH_FISH@163.COM, gender=1], Employee [id=2, lastName=2, email=2, gender=1]]

foreach批量保存

接口EmployeeMapper.java

/**
 * 动态sql foreach 批量添加
 * @Author ZFH
 * @Date 2019年7月29日
 */
public void addEmployee(@Param("emps") List<Employee> emps);

配置文件EmployeeMapper.xml

<insert id="addEmployee">
    insert into tbl_employee(last_name,email,gender,d_id) values 
    <foreach collection="emps" item="emp" separator=",">
        (#{emp.lastName},#{emp.email},#{emp.gender},#{emp.department.id})
    </foreach>
</insert>

测试类

@org.junit.Test
public void test06() throws IOException {
    //读取配置文件
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    //获取SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession openSession = sqlSessionFactory.openSession();
    //调用getMapper方法获取该接口的实现类
    EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);

    List<Employee> list = new ArrayList<Employee>();
    Department department = new Department();
    department.setId(1);
    Department department2 = new Department();
    department2.setId(2);
    list.add(new Employee(null,"李四","zfh@163.com","1",department));
    list.add(new Employee(null,"李四2","zfh@163.com","0",department2));
    mapper.addEmployee(list);

    openSession.commit();
    //关闭Session
    openSession.close();

}

运行结果

mybatis内置参数

mybatis有两个内置参数:_parameter,_databaseId
  • _parameter:代表整个参数 
    • 单个参数: _parameter就是这个参数
    • 多个参数: 参数会被封装为一个map: _parameter就是代表这个map
  • _databaseId:如果配置了databaseIdProvider标签. 
    • _databaseId就是代表当前数据库的别名,例如: oracle

bind标签

接口(EmployeeMapper.java)

/**
 * 使用bind标签
 */
public List<Employee> selEmpByNameBind(String lastName);

配置文件(EmployeeMapper.xml)

<select id="selEmpByNameBind" resultType="com.fish.pojo.Employee">
<bind name="_lastName" value="'%'+_parameter+'%'"/><!--这里取值用mybatis的内置参数取,用参数名取不到,不知道什么原因,有知道的小伙伴可以告知一下-->
    select * from tbl_employee 
        <where>
             last_name like #{_lastName}
        </where>
</select>

测试类

@org.junit.Test
public void test07() throws IOException {
    //读取配置文件
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    //获取SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession openSession = sqlSessionFactory.openSession();
    //调用getMapper方法获取该接口的实现类
    EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
    List<Employee> selEmpByNameBind = mapper.selEmpByNameBind("四");
    System.out.println(selEmpByNameBind);

    //关闭Session
    openSession.close();

}

sql标签(抽取可重用sql片段)

接口(EmployeeMapper.java)

/**
 * 使用sql标签
 */
public List<Employee> selEmpByNamesql(String lastName);

配置文件(EmployeeMapper.xml)

<!-- 
    抽取可重用的sql片段,方便后面引用
    1, sql抽取:京城将要查询的列名,或者插入用的列名抽取出来方便引用
    2, include来引用已经抽取的sql
    3, include还可以自定义一些property,sql标签内部就能使用自定义的属性
        inclyde-property:取值的正确方式${prop},
			不能用#{prop}这种方式
	 -->
	<sql id="selColumn">
		id,last_name,gender,${email2}<!--这里我觉得并没有实际的意义,可能是我还没有理解到精髓吧,以后了解了回来更新-->
</sql>
<select id="selEmpByNamesql" resultType="com.fish.pojo.Employee">
<bind name="_lastName" value="'%'+_parameter+'%'"/>
    select 
        <include refid="selColumn">
            <property name="email2" value="email"/>
        </include>
    from tbl_employee 
        <where>
             last_name like "%" #{_lastName} ""
        </where>
</select>

测试类

@org.junit.Test
public void test08() throws IOException {
    //读取配置文件
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    //获取SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession openSession = sqlSessionFactory.openSession();
    //调用getMapper方法获取该接口的实现类
    EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
    List<Employee> selEmpByNameBind = mapper.selEmpByNamesql("四");
    System.out.println(selEmpByNameBind);

    //关闭Session
    openSession.close();

}

+

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!