MyBatis动态SQL(转载)

本文转载自:https://zhuanlan.zhihu.com/p/40530920,略做修改

一、前言

什么是 Mybatis 动态 SQL 呢?

根据用户提供的参数,动态决定查询语句依赖的条件或者SQL语句的具体内容,这就是动态SQL。

本文主要介绍 Mybatis 动态 SQL的四种主要标签组合:

  1. if、where
  2. choose、when、otherwise
  3. trim、where、set
  4. foreach

这些标签在开发过程中无处不在,能够解决数据查询方面的绝大部分问题;有了它们,你的 SQL 才更灵活。

二、首生成数据结构和测试数据(MySQL)

CREATE TABLE `dept` (
  `DEPTNO` INT NOT NULL AUTO_INCREMENT,
  `DNAME` VARCHAR(45) NOT NULL,
  `LOC` VARCHAR(45) NOT NULL,
  `DATE` DATE NULL,
  `CITY` VARCHAR(45) NULL,
  PRIMARY KEY (`DEPTNO`),
  UNIQUE INDEX `DNAME_UNIQUE` (`DNAME` ASC));
  
INSERT INTO `dept` (`DEPTNO`, `DNAME`, `LOC`, `DATE`, `CITY`) VALUES ('1', '开发部', '上海开发中心', '2021-1-1', '上海');
INSERT INTO `dept` (`DEPTNO`, `DNAME`, `LOC`, `DATE`, `CITY`) VALUES ('2', '市场部', '北京市场中心', '2019-1-1', '北京');
INSERT INTO `dept` (`DEPTNO`, `DNAME`, `LOC`, `DATE`, `CITY`) VALUES ('3', '财务部', '北京天通苑', '2020-1-1', '北京');
INSERT INTO `dept` (`DEPTNO`, `DNAME`, `LOC`, `DATE`, `CITY`) VALUES ('4', '营销部', '上海虹桥', '2018-1-1', '上海');

三、动态 SQL 标签

(一)if 标签和 where 标签的使用

1. xml 代码:

    <select id="findList1" resultType="Dept">
        select deptno,dname,loc,date from dept
        <where>
            <if test="deptno != null and deptno != 0">
                and deptno = #{deptno}
            </if>
            <if test="dname != null and dname != ''">
                and dname = #{dname}
            </if>
            <if test="loc != null and loc != ''">
                and loc = #{loc}
            </if>
        </where>
    </select>

2. Java 接口代码:

    List<Dept> findList1(Dept dept);

3. Java测试代码:

    @Test
    public void test01() throws IOException {
        DeptMapper deptMapper = session.getMapper(DeptMapper.class);
        Dept dept = new Dept();
        dept.setDeptno(2);
        dept.setDname("市场部");
        List<Dept> list = deptMapper.findList1(dept);
        list.forEach(item -> System.out.println(item));
    }

4. 运行结果:

被拦截方法执行之前,做的辅助服务······
[DEBUG] Opening JDBC Connection
[DEBUG] Created connection 1516500233.
[DEBUG] Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@5a63f509]
[DEBUG] ==>  Preparing: select deptno,dname,loc,date from dept WHERE deptno = ? and dname = ? 
[DEBUG] ==> Parameters: 2(Integer), 市场部(String)
[DEBUG] <==      Total: 1
被拦截方法执行之后,做的辅助服务······
Dept{deptno=2, dname='市场部', loc='北京市场中心', city='null', date=Tue Jan 01 00:00:00 CST 2019}
[DEBUG] Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@5a63f509]
[DEBUG] Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@5a63f509]
[DEBUG] Returned connection 1516500233 to pool.

5. 解读日志

我们只给 deptno 和 dname 进行了赋值,而没有对 loc 属性进行赋值,所以在 SQL 参数中没有出现 loc 字段,也就表名 loc 为空,导致 “and loc = #{loc}”没有被执行。

一般开发列表业务的查询条件时,如果有多个查询条件,通常会使用 <if> 标签来进行控制。

<where> 标签可以自动的将第一个条件前面的逻辑运算符 (or ,and) 去掉,正如代码中写的,deptno 查询条件前面是有“and”关键字的,但是在打印出来的 SQL 中却没有,这就是 <where> 的作用。

(二)choose、when、otherwise 标签的使用

1. xml 代码:

    <select id="findList2" resultType="Dept">
        select deptno,dname,loc,date from dept
        <where>
            <choose>
                <when test="dname != null and dname != ''">
                    and dname like '%' #{dname} '%'
                </when>
                <when test="loc != null and loc != ''">
                    and loc = #{loc}
                </when>
                <otherwise>
                    and deptno = #{deptno}
                </otherwise>
            </choose>
        </where>
    </select>

2. Java接口代码:

  List<Dept> findList2(Dept dept);

3. Java测试代码:

    @Test
    public void test02() throws IOException {
        DeptMapper deptMapper = session.getMapper(DeptMapper.class);
        Dept dept = new Dept();
        dept.setDeptno(2);
        List<Dept> list = deptMapper.findList2(dept);
        list.forEach(item -> System.out.println(item));
    }

4. 运行结果:

被拦截方法执行之前,做的辅助服务······
[DEBUG] Opening JDBC Connection
[DEBUG] Created connection 1516500233.
[DEBUG] Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@5a63f509]
[DEBUG] ==>  Preparing: select deptno,dname,loc,date from dept WHERE deptno = ? 
[DEBUG] ==> Parameters: 2(Integer)
[DEBUG] <==      Total: 1
被拦截方法执行之后,做的辅助服务······
Dept{deptno=2, dname='市场部', loc='北京市场中心', city='null', date=Tue Jan 01 00:00:00 CST 2019}
[DEBUG] Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@5a63f509]
[DEBUG] Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@5a63f509]
[DEBUG] Returned connection 1516500233 to pool.

5. 解读日志

这三个标签需要组合在一起使用,类似于 Java 中的 switch、case、default。只有一个条件生效,也就是只执行满足的条件 when,没有满足的条件就执行 otherwise,表示默认条件。

这个应该很好理解吧。

这里我们的测试用例中只给出了一个参数就是 deptno,没有给出 dname 以及 loc 参数,所以直接执行了 otherwise 中的代码,这里就不再过多的进行赘述。

(三)set 标签的使用

1. xml 代码:

    <update id="update">
        update dept
        <set>
            <if test="dname != null and dname != ''">
                dname = #{dname},
            </if>
            <if test="loc != null and loc != ''">
                loc = #{loc},
            </if>
        </set>
        where deptno = #{deptno}
    </update>

2. Java接口代码:

    void update(Dept dept);

3. Java测试代码:

    @Test
    public void test03() throws IOException {
        DeptMapper deptMapper = session.getMapper(DeptMapper.class);
        Dept dept = new Dept();
        dept.setDeptno(2);
        dept.setDname("河北香河中心");
        deptMapper.update(dept);
        session.commit();
    }

4. 运行结果:

[DEBUG] Opening JDBC Connection
[DEBUG] Created connection 1923598304.
[DEBUG] Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@72a7c7e0]
[DEBUG] ==>  Preparing: update dept SET dname = ? where deptno = ? 
[DEBUG] ==> Parameters: 河北香河中心(String), 2(Integer)
[DEBUG] <==    Updates: 1
[DEBUG] Committing JDBC Connection [com.mysql.jdbc.JDBC4Connection@72a7c7e0]
[DEBUG] Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@72a7c7e0]
[DEBUG] Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@72a7c7e0]
[DEBUG] Returned connection 1923598304 to pool.

5. 解读日志

<set> 标签会在成功拼接的条件前加上 SET 单词且最后一个“,”号会被无视掉,如 xml 代码中所示,“loc = #{loc},”代码并没有被执行,而“dname = #{dname}”代码后面的“,”已经被去掉了,这就是 <set> 的作用。

在进行表单更新的操作中,哪个字段中有值才去更新,没有值就不做任何操作,这就需要结合使用 <set> 标签和 <if> 标签了。

(四)trim 标签的使用

先说一下 trim 标签4个参数:

  •  prefix:前缀
  •  prefixOverrides:去掉第一个and或者是or
  •  suffix:后缀
  •  suffixOverrides:去掉最后一个逗号(也可以是其他的标记,就像是上面前缀中的and一样)

1. xml 代码:

    <!--
        prefix:前缀
        prefixOverrides:去掉第一个and或者是or
        suffix:后缀
        suffixOverrides:去掉最后一个逗号(也可以是其他的标记,就像是上面前缀中的and一样)
     -->
    <select id="findList3" resultType="Dept">
        select deptno,dname,loc,date from dept
        <trim prefix="where" prefixOverrides="and | or" suffix="order by deptno" suffixOverrides=",">
            <if test="deptno != null and deptno != 0">
                and deptno = #{deptno}
            </if>
            <if test="dname != null and dname != ''">
                and dname = #{dname}
            </if>
            <if test="loc != null and loc != ''">
                and loc = #{loc}
            </if>
        </trim>
    </select>

2. Java接口代码:

  List<Dept> findList3(Dept dept);

3. Java测试代码:

    @Test
    public void test04() throws IOException {
        DeptMapper deptMapper = session.getMapper(DeptMapper.class);
        Dept dept = new Dept();
        dept.setDeptno(1);
        dept.setDname("开发部");
        List<Dept> list = deptMapper.findList3(dept);
        list.forEach(item -> System.out.println(item));
    }

4. 运行结果:

被拦截方法执行之前,做的辅助服务······
[DEBUG] Opening JDBC Connection
[DEBUG] Created connection 1516500233.
[DEBUG] Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@5a63f509]
[DEBUG] ==>  Preparing: select deptno,dname,loc,date from dept where deptno = ? and dname = ? order by deptno 
[DEBUG] ==> Parameters: 1(Integer), 开发部(String)
[DEBUG] <==      Total: 1
被拦截方法执行之后,做的辅助服务······
Dept{deptno=1, dname='开发部', loc='上海开发中心', city='null', date=Fri Jan 01 00:00:00 CST 2021}
[DEBUG] Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@5a63f509]
[DEBUG] Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@5a63f509]
[DEBUG] Returned connection 1516500233 to pool.

5. 解读日志

<trim> 标签是一个格式化的标签,可以完成 <set> 或者是 <where> 标记的功能,从打印出的 SQL 语句中可以看出。

我们代码中并没有写“where”,但是打印出的 SQL 中却有,这是为什么呢?

这是因为 <trim> 标签中 prefix="where" 属性的缘故,这就是它的作用,而后面的 “order by deptno”,则是由于 suffix="order by deptno" 属性的缘故,prefixOverrides="and | or" 和 suffixOverrides="," 则与 <where> 和 <set> 作用相同。

(五)foreach 标签的使用

对于 <foreach> 标签,我们会根据4个例子来进行演示,主要有批量插入,list 集合参数、array 集合参数以及 map 集合参数。我们先来看一下 <foreach> 标签的参数:

  • item:表示集合中每一个元素进行迭代的别名
  • index:指定一个名字,用于表示在迭代过程中,每次迭代到的位置
  • open:表示该语句以什么开始
  • close:表示该语句以什么结束
  • separator:表示每次进行迭代之间以什么符号做为分隔符

 1)批量插入

1. xml 代码:

    <!--
        item:表示集合中每一个元素进行迭代的别名
        index:指定一个名字,用于表示在迭代过程中,每次迭代到的位置
        open:表示该语句以什么开始
        close:表示该语句以什么结束
        separator:表示每次进行迭代之间以什么符号做为分隔符
    -->
    <insert id="insertBatch">
        INSERT INTO dept (dname,loc)
        VALUES
        <foreach collection="list" item="dept" separator=",">
            (#{dept.dname},#{dept.loc})
        </foreach>
    </insert>

2. Java接口代码: 

    void insertBatch(List<Dept> deptList);

3. Java测试代码:

    @Test
    public void test05() throws IOException {
        DeptMapper deptMapper = session.getMapper(DeptMapper.class);
        List<Dept> deptList = new ArrayList<>();
        Dept dept = new Dept();
        dept.setDname("技术研发部");
        dept.setLoc("聊城");
        deptList.add(dept);
        dept = new Dept();
        dept.setDname("科技事业部");
        dept.setLoc("济南");
        deptList.add(dept);
        deptMapper.insertBatch(deptList);
        session.commit();
    }

4. 运行结果: 

[DEBUG] Opening JDBC Connection
[DEBUG] Created connection 1629687658.
[DEBUG] Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@61230f6a]
[DEBUG] ==>  Preparing: INSERT INTO dept (dname,loc) VALUES (?,?) , (?,?) 
[DEBUG] ==> Parameters: 技术研发部(String), 聊城(String), 科技事业部(String), 济南(String)
[DEBUG] <==    Updates: 2
[DEBUG] Committing JDBC Connection [com.mysql.jdbc.JDBC4Connection@61230f6a]
[DEBUG] Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@61230f6a]
[DEBUG] Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@61230f6a]
[DEBUG] Returned connection 1629687658 to pool.

5. 解读日志

从结果可以看出,我们一下插入了两条数据,每条数据之间使用“,”进行分割,separator="," 的作用就是如此,批量插入操作在日常的开发中也是经常使用的,也是必须掌握的知识点。

2)list 集合参数

1. xml 代码:

    <select id="findList4" resultType="Dept">
        select deptno,dname,loc,date from dept
        where deptno in
        <foreach collection="list" item="deptno" open="(" close=")" separator=",">
            #{deptno}
        </foreach>
    </select>

2. Java接口代码: 

    List<Dept> findList4(List<Integer> deptnoList);

3. Java测试代码:

    @Test
    public void test06() throws IOException {
        DeptMapper deptMapper = session.getMapper(DeptMapper.class);
        List<Integer> deptnoList = new ArrayList<>();
        deptnoList.add(5);
        deptnoList.add(6);
        List<Dept> list = deptMapper.findList4(deptnoList);
        list.forEach(item -> System.out.println(item));
    }

4. 运行结果: 

被拦截方法执行之前,做的辅助服务······
[DEBUG] Opening JDBC Connection
[DEBUG] Created connection 1882554559.
[DEBUG] Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@703580bf]
[DEBUG] ==>  Preparing: select deptno,dname,loc,date from dept where deptno in ( ? , ? ) 
[DEBUG] ==> Parameters: 5(Integer), 6(Integer)
[DEBUG] <==      Total: 2
被拦截方法执行之后,做的辅助服务······
Dept{deptno=5, dname='技术研发部', loc='聊城', city='null', date=null}
Dept{deptno=6, dname='科技事业部', loc='济南', city='null', date=null}
[DEBUG] Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@703580bf]
[DEBUG] Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@703580bf]
[DEBUG] Returned connection 1882554559 to pool

5. 解读日志

从打印的 SQL 语句可以看出,这个 <foreach> 标签为我们提供了这样一段 SQL 代码:( ? , ? ) ,前后的括号由 open="(" close=")" 进行控制,内涵两个循环遍历出的元素,用“?”占位符占位,并用“,”隔开。array 集合与 list 及其相似,这里给出 SQL 语句、接口、调用,就不再多赘述了。

    <select id="findList5" resultType="Dept">
        select deptno,dname,loc,date from dept
        where deptno in
        <foreach collection="array" item="deptno" open="(" close=")" separator=",">
            #{deptno}
        </foreach>
    </select>
    List<Dept> findList5(int[] deptnos);
    @Test
    public void test07() throws IOException {
        DeptMapper deptMapper = session.getMapper(DeptMapper.class);
        int[] deptnos = new int[2];
        deptnos[0] = 5;
        deptnos[1] = 6;
        List<Dept> list = deptMapper.findList5(deptnos);
        list.forEach(item -> System.out.println(item));
    }

3)map 集合参数

1. xml 代码: 

    <select id="findList6" resultType="Dept">
        select deptno,dname,loc,date from dept
        where deptno in
        <foreach collection="myMap.values" item="deptno" open="(" close=")" separator=",">
            #{deptno}
        </foreach>
    </select>

2. Java接口代码: 

    List<Dept> findList6(@Param("myMap") Map<String, Integer> map);

 3. Java测试代码: 

    @Test
    public void test08() throws IOException {
        DeptMapper deptMapper = session.getMapper(DeptMapper.class);
        Map<String, Integer> map = new HashMap<>();
        map.put("key1",5);
        map.put("key2",6);
        List<Dept> list = deptMapper.findList6(map);
        list.forEach(item -> System.out.println(item));
    }

4. 运行结果: 

被拦截方法执行之前,做的辅助服务······
[DEBUG] Opening JDBC Connection
[DEBUG] Created connection 1629687658.
[DEBUG] Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@61230f6a]
[DEBUG] ==>  Preparing: select deptno,dname,loc,date from dept where deptno in ( ? , ? ) 
[DEBUG] ==> Parameters: 5(Integer), 6(Integer)
[DEBUG] <==      Total: 2
被拦截方法执行之后,做的辅助服务······
Dept{deptno=5, dname='技术研发部', loc='聊城', city='null', date=null}
Dept{deptno=6, dname='科技事业部', loc='济南', city='null', date=null}
[DEBUG] Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@61230f6a]
[DEBUG] Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@61230f6a]
[DEBUG] Returned connection 1629687658 to pool.

 5. 解读日志

从结果我们可以看出,打印出的 SQL 与 list 参数的结果是完全一致的,这里我们使用到了 Mybatis 的参数注解 @Param(),在这里这个参数是必不可少的。

因为 <foreach> 标签中的 collection="myMap.values" 属性是这样写的,我们要告知 Mybatis “myMap”是一个参数对象,而我们用的则是这个对象中的“values”,就相当于 Java 中我们的 map 对象调用 values 对象(Collection<Integer> values = map.values();),这里就相当于是对这个 values 集合进行遍历。

四、总结

动态 SQL 的标签就这些,我们已经都讲解过了,内容还是比较多的,一定要自己动手写一写单元测试,并且掌握每一种标签的不同使用场景,学会了他们,解决日常开发中的业务逻辑就会轻松很多。

五、全部代码下载

Dept.java

package top.alanshelby.mybatis.bean;

import java.util.Date;

public class Dept {

    private Integer deptno;
    private String dname;
    private String loc;
    private Date date;
    private String city;

    public Integer getDeptno() {
        return deptno;
    }

    public void setDeptno(Integer deptno) {
        this.deptno = deptno;
    }

    public String getDname() {
        return dname;
    }

    public void setDname(String dname) {
        this.dname = dname;
    }

    public String getLoc() {
        return loc;
    }

    public void setLoc(String loc) {
        this.loc = loc;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    @Override
    public String toString() {
        return "Dept{" +
                "deptno=" + deptno +
                ", dname='" + dname + '\'' +
                ", loc='" + loc + '\'' +
                ", city='" + city + '\'' +
                ", date=" + date +
                '}';
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }
}
View Code

DeptMapper.java

package top.alanshelby.mybatis.dao;


import org.apache.ibatis.annotations.Param;
import top.alanshelby.mybatis.bean.Dept;

import java.util.List;
import java.util.Map;

public interface DeptMapper {

    List<Dept> findList1(Dept dept);

    List<Dept> findList2(Dept dept);

    void update(Dept dept);

    List<Dept> findList3(Dept dept);

    void insertBatch(List<Dept> deptList);

    List<Dept> findList4(List<Integer> deptnoList);

    List<Dept> findList5(int[] deptnos);

    List<Dept> findList6(@Param("myMap") Map<String, Integer> map);
}
View Code

MyInterceptor.java

package top.alanshelby.mybatis.util;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.util.Properties;

@Intercepts(
        @Signature(method = "query",
                type = Executor.class,
                args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
        )
)
public class MyInterceptor implements Interceptor {

    /**
     * @param invocation { 代理对象,被监控方法对象,当前被监控方法运行时需要的实参 }
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("被拦截方法执行之前,做的辅助服务······");
        Object proceed = invocation.proceed();
        System.out.println("被拦截方法执行之后,做的辅助服务······");
        return proceed;
    }

    /**
     * @param target 表示被拦截的对象,此处为 Executor 的实例对象
     *               作用:如果被拦截对象所在的类有实现接口,就为当前拦截对象生成一个代理对象
     *               如果被拦截对象所在的类没有指定接口,这个对象之后的行为就不会被代理操作
     * @return
     */
    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }
}
View Code

AppTest.java

package top.alanshelby;

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.After;
import org.junit.Before;
import org.junit.Test;
import top.alanshelby.mybatis.bean.Dept;
import top.alanshelby.mybatis.dao.DeptMapper;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

public class AppTest {

    private SqlSession session;

    @Before
    public void start() {
        try {
            InputStream inputStream = Resources.getResourceAsStream("myBatis-config_top.xml");
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
            session = factory.openSession();
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }

    @Test
    public void test01() throws IOException {
        DeptMapper deptMapper = session.getMapper(DeptMapper.class);
        Dept dept = new Dept();
        dept.setDeptno(2);
        dept.setDname("市场部");
        List<Dept> list = deptMapper.findList1(dept);
        list.forEach(item -> System.out.println(item));
    }

    @Test
    public void test02() throws IOException {
        DeptMapper deptMapper = session.getMapper(DeptMapper.class);
        Dept dept = new Dept();
        dept.setDeptno(2);
        List<Dept> list = deptMapper.findList2(dept);
        list.forEach(item -> System.out.println(item));
    }

    @Test
    public void test03() throws IOException {
        DeptMapper deptMapper = session.getMapper(DeptMapper.class);
        Dept dept = new Dept();
        dept.setDeptno(2);
        dept.setDname("河北香河中心");
        deptMapper.update(dept);
        session.commit();
    }

    @Test
    public void test04() throws IOException {
        DeptMapper deptMapper = session.getMapper(DeptMapper.class);
        Dept dept = new Dept();
        dept.setDeptno(1);
        dept.setDname("开发部");
        List<Dept> list = deptMapper.findList3(dept);
        list.forEach(item -> System.out.println(item));
    }

    @Test
    public void test05() throws IOException {
        DeptMapper deptMapper = session.getMapper(DeptMapper.class);
        List<Dept> deptList = new ArrayList<>();
        Dept dept = new Dept();
        dept.setDname("技术研发部");
        dept.setLoc("聊城");
        deptList.add(dept);
        dept = new Dept();
        dept.setDname("科技事业部");
        dept.setLoc("济南");
        deptList.add(dept);
        deptMapper.insertBatch(deptList);
        session.commit();
    }

    @Test
    public void test06() throws IOException {
        DeptMapper deptMapper = session.getMapper(DeptMapper.class);
        List<Integer> deptnoList = new ArrayList<>();
        deptnoList.add(5);
        deptnoList.add(6);
        List<Dept> list = deptMapper.findList4(deptnoList);
        list.forEach(item -> System.out.println(item));
    }

    @Test
    public void test07() throws IOException {
        DeptMapper deptMapper = session.getMapper(DeptMapper.class);
        int[] deptnos = new int[2];
        deptnos[0] = 5;
        deptnos[1] = 6;
        List<Dept> list = deptMapper.findList5(deptnos);
        list.forEach(item -> System.out.println(item));
    }

    @Test
    public void test08() throws IOException {
        DeptMapper deptMapper = session.getMapper(DeptMapper.class);
        Map<String, Integer> map = new HashMap<>();
        map.put("key1",5);
        map.put("key2",6);
        List<Dept> list = deptMapper.findList6(map);
        list.forEach(item -> System.out.println(item));
    }

    @After
    public void end() {
        if (session != null) {
            session.close();
        }
    }

}
View Code

DeptMapper.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="top.alanshelby.mybatis.dao.DeptMapper">

    <select id="findList1" resultType="Dept">
        select deptno,dname,loc,date from dept
        <where>
            <if test="deptno != null and deptno != 0">
                and deptno = #{deptno}
            </if>
            <if test="dname != null and dname != ''">
                and dname = #{dname}
            </if>
            <if test="loc != null and loc != ''">
                and loc = #{loc}
            </if>
        </where>
    </select>

    <select id="findList2" resultType="Dept">
        select deptno,dname,loc,date from dept
        <where>
            <choose>
                <when test="dname != null and dname != ''">
                    and dname like '%' #{dname} '%'
                </when>
                <when test="loc != null and loc != ''">
                    and loc = #{loc}
                </when>
                <otherwise>
                    and deptno = #{deptno}
                </otherwise>
            </choose>
        </where>
    </select>

    <update id="update">
        update dept
        <set>
            <if test="dname != null and dname != ''">
                dname = #{dname},
            </if>
            <if test="loc != null and loc != ''">
                loc = #{loc},
            </if>
        </set>
        where deptno = #{deptno}
    </update>

    <!--
        prefix:前缀
        prefixOverrides:去掉第一个and或者是or
        suffix:后缀
        suffixOverrides:去掉最后一个逗号(也可以是其他的标记,就像是上面前缀中的and一样)
     -->
    <select id="findList3" resultType="Dept">
        select deptno,dname,loc,date from dept
        <trim prefix="where" prefixOverrides="and | or" suffix="order by deptno" suffixOverrides=",">
            <if test="deptno != null and deptno != 0">
                and deptno = #{deptno}
            </if>
            <if test="dname != null and dname != ''">
                and dname = #{dname}
            </if>
            <if test="loc != null and loc != ''">
                and loc = #{loc}
            </if>
        </trim>
    </select>

    <!--
        item:表示集合中每一个元素进行迭代的别名
        index:指定一个名字,用于表示在迭代过程中,每次迭代到的位置
        open:表示该语句以什么开始
        close:表示该语句以什么结束
        separator:表示每次进行迭代之间以什么符号做为分隔符
    -->
    <insert id="insertBatch">
        INSERT INTO dept (dname,loc)
        VALUES
        <foreach collection="list" item="dept" separator=",">
            (#{dept.dname},#{dept.loc})
        </foreach>
    </insert>

    <select id="findList4" resultType="Dept">
        select deptno,dname,loc,date from dept
        where deptno in
        <foreach collection="list" item="deptno" open="(" close=")" separator=",">
            #{deptno}
        </foreach>
    </select>

    <select id="findList5" resultType="Dept">
        select deptno,dname,loc,date from dept
        where deptno in
        <foreach collection="array" item="deptno" open="(" close=")" separator=",">
            #{deptno}
        </foreach>
    </select>

    <select id="findList6" resultType="Dept">
        select deptno,dname,loc,date from dept
        where deptno in
        <foreach collection="myMap.values" item="deptno" open="(" close=")" separator=",">
            #{deptno}
        </foreach>
    </select>

</mapper>
View Code

myBatis-config_top.xml

<?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>

    <properties resource="db.properties"></properties>
    
    <typeAliases>
        <package name="top.alanshelby.mybatis.bean"/>
    </typeAliases>

    <typeHandlers>
        <typeHandler handler="top.alanshelby.mybatis.util.MyDateTypeHandler" javaType="java.util.Date"
                     jdbcType="VARCHAR"/>
    </typeHandlers>

    <plugins>
        <plugin interceptor="top.alanshelby.mybatis.util.MyInterceptor"></plugin>
    </plugins>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <package name="top.alanshelby.mybatis.dao"/>
    </mappers>

</configuration>
View Code

db.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/xuejia?useUnicode=true&characterEncoding=utf-8
jdbc.username=root
jdbc.password=admin
View Code

log4j.properties

##define an appender named console
log4j.appender.console=org.apache.log4j.ConsoleAppender
#The Target value is System.out or System.err
log4j.appender.console.Target=System.out
#set the layout type of the apperder
log4j.appender.console.layout=org.apache.log4j.PatternLayout
#set the layout format pattern
log4j.appender.console.layout.ConversionPattern=[%-5p] %m%n

##define a logger
log4j.rootLogger=debug,console
View Code

 

posted @ 2021-08-22 20:37  那些年的事儿  阅读(95)  评论(0编辑  收藏  举报