MyBatis从入门到精通

MyBatis

MyBatis 是一款优秀的半自动的ORM持久层框架,它支持自定义 SQL、存储过程以及高级映射。

MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。

MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

持久层:可以立即保存在磁盘上,在这里可以理解为与数据库相关操作。

  1. 什么是ORM

    OBject Relation Mapping 对象关系映射

    对象指的是面向面向对象,关系指的是数据库中的表,

    例如Java语言中的POJO类与数据库模型之间的对应关系。

    ORM
    MyBatis从入门到精通_第1张图片
    MyBatis从入门到精通_第2张图片

  2. 为什么MyBatis是半自动ORM框架

    public class User(){
        private long id;
        private String realname;
    }
    
    User user = user .getById(3);
    
    SELECT `id`,`realname` FROM `user` WHERE `id` = 3;
    

    以上用例为ORM框架部分执行代码,发现在ORM框架中不需要使用SQL语句,

    大大减少了程序员学习成本和SQL语句维护成本,

    另外当数据库产品更换的之后无需重新编写项目中的SQL语句

    -- MySQL
    SELECT * FROM `user` LIMIT 10;
    
    -- SqlServer
    SELECT * FROM `user` TOP 10;
    

    用MyBatis进行开发的,需要手写SQL语句,而ORM框架例如Hibernate则不需要编写SQL语句。

  3. 为什么MyBais是半自动ORM框架我们还要去学习呢

    因为MyBatis使用自定义SQL所以更加灵活尤其在多表操作

MyBaits工作原理

JDBC核心对象

  1. DriverManager,数据库驱动管理对象
  2. Connection,数据库连接对象
  3. Statement | PrepareStatement ,操作数据库SQL语句对象
  4. ResultSet,结果集对象

MyBaits核心对象

  1. SqlSession对象,该对象包含了执行SQL语句的所有方法,例如JDBC里面Connection

    对象 说明
    Executor接口 执行器.统一调度其他三个对象执行对应的SQL
    StatementHandler 使用的数据库中的Statement执行操作 相当于字符串拼接
    PrepareStatement 使用SQL传参的方式处理
    ResultHandler 对最后的结果进行封装
  2. Executor接口,将传递过来的参数动态生成SQL语句,负责查询缓存。

  3. MappedStatement对象,该对象负责对SQL封装,用于存储需要映射的SQL语句及参数等信息

  4. ResultHandler对象,用户返回结果集合,封装成最红想要的数据类型,可以自定义返回类型

MyBatis执行流程

MyBatis从入门到精通_第3张图片

快速上门

新建maven项目并导入相关依赖

mvn archetype:generate

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0modelVersion>

  <groupId>com.lihaozhegroupId>
  <artifactId>mybatisartifactId>
  <version>1.0-SNAPSHOTversion>
  <name>mybatisname>
  <packaging>jarpackaging>

  <properties>
    <jdk.version>17jdk.version>
    <maven.compiler.source>17maven.compiler.source>
    <maven.compiler.target>17maven.compiler.target>
    <maven.compiler.compilerVersion>17maven.compiler.compilerVersion>
    <maven.compiler.encoding>utf-8maven.compiler.encoding>
    <project.build.sourceEncoding>utf-8project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
    <maven.test.failure.ignore>truemaven.test.failure.ignore>
    <maven.test.skip>truemaven.test.skip>
    <junit.version>5.8.2junit.version>

    <fastjson.version>2.0.6fastjson.version>
    <gson.version>2.9.0gson.version>
    <hutool.version>5.8.0.M3hutool.version>
    <jackson.version>2.13.3jackson.version>
    <lombok.version>1.18.24lombok.version>
    <java-testdata.version>1.1.2java-testdata.version>
  properties>

  <dependencies>
    <dependency>
      <groupId>org.junit.jupitergroupId>
      <artifactId>junit-jupiter-apiartifactId>
      <version>${junit.version}version>
      <scope>testscope>
    dependency>
    <dependency>
      <groupId>com.github.binarywanggroupId>
      <artifactId>java-testdata-generatorartifactId>
      <version>${java-testdata.version}version>
    dependency>
    
    
    <dependency>
      <groupId>org.apache.commonsgroupId>
      <artifactId>commons-lang3artifactId>
      <version>3.8.1version>
    dependency>
    
    <dependency>
      <groupId>commons-iogroupId>
      <artifactId>commons-ioartifactId>
      <version>2.11.0version>
    dependency>
    <dependency>
      <groupId>org.junit.jupitergroupId>
      <artifactId>junit-jupiter-engineartifactId>
      <version>${junit.version}version>
      <scope>testscope>
    dependency>
    <dependency>
      <groupId>cn.hutoolgroupId>
      <artifactId>hutool-allartifactId>
      <version>${hutool.version}version>
    dependency>
    <dependency>
      <groupId>org.projectlombokgroupId>
      <artifactId>lombokartifactId>
      <version>${lombok.version}version>
      <scope>providedscope>
    dependency>
    
    
    <dependency>
      <groupId>com.alibabagroupId>
      <artifactId>fastjsonartifactId>
      <version>${fastjson.version}version>
    dependency>
    
    <dependency>
      <groupId>com.google.code.gsongroupId>
      <artifactId>gsonartifactId>
      <version>${gson.version}version>
    dependency>
    
    <dependency>
      <groupId>com.fasterxml.jackson.coregroupId>
      <artifactId>jackson-coreartifactId>
      <version>${jackson.version}version>
    dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.coregroupId>
      <artifactId>jackson-annotationsartifactId>
      <version>${jackson.version}version>
    dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.coregroupId>
      <artifactId>jackson-databindartifactId>
      <version>${jackson.version}version>
    dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.datatypegroupId>
      <artifactId>jackson-datatype-jsr310artifactId>
      <version>${jackson.version}version>
    dependency>
    <dependency>
      <groupId>mysqlgroupId>
      <artifactId>mysql-connector-javaartifactId>
      <version>8.0.29version>
    dependency>
    <dependency>
      <groupId>org.mybatisgroupId>
      <artifactId>mybatisartifactId>
      <version>3.5.10version>
    dependency>
    <dependency>
      <groupId>com.alibabagroupId>
      <artifactId>druidartifactId>
      <version>1.2.8version>
    dependency>
    <dependency>
      <groupId>org.springframeworkgroupId>
      <artifactId>spring-contextartifactId>
      <version>5.3.20version>
    dependency>
    <dependency>
      <groupId>org.slf4jgroupId>
      <artifactId>slf4j-simpleartifactId>
      <version>1.7.36version>
    dependency>
  dependencies>

  <build>
    
    
    <plugins>
      <plugin>
        <groupId>org.apache.maven.pluginsgroupId>
        <artifactId>maven-war-pluginartifactId>
        <version>3.3.2version>
      plugin>
      
      <plugin>
        <groupId>org.apache.maven.pluginsgroupId>
        <artifactId>maven-compiler-pluginartifactId>
        <version>3.8.1version>
        <configuration>
          
          <encoding>UTF-8encoding>
          
          <source>${jdk.version}source>
          <target>${jdk.version}target>
        configuration>
      plugin>
      <plugin>
        <groupId>org.apache.maven.pluginsgroupId>
        <artifactId>maven-clean-pluginartifactId>
        <version>3.2.0version>
      plugin>
      <plugin>
        <groupId>org.apache.maven.pluginsgroupId>
        <artifactId>maven-resources-pluginartifactId>
        <version>3.2.0version>
      plugin>
      
      <plugin>
        <groupId>org.apache.maven.pluginsgroupId>
        <artifactId>maven-surefire-pluginartifactId>
        <version>2.22.2version>
        <configuration>
          <skip>trueskip>
        configuration>
      plugin>
    plugins>
  build>
project>

根据数据表生成对应POJO类

MyBatis从入门到精通_第4张图片
点击下载数据库脚本文件

编写数据源文件

src/main/resources/config.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql:///mybatis?useUnicode=true&characterEncoding=UTF8&useSSL=false&useServerPrepStmts=false&rewriteBatchedStatements=true&cachePrepStmts=true&allowMultiQueries=true&serverTimeZone=Aisa/Shanghai
username=root
password=123456

编写核心配置文件

src/main/resources/mybatis/mybatis-config.xml


DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    
    <properties resource="config.properties" />
    
    
    <environments default="development">
        
        <environment id="development">
            
            
            <transactionManager type="JDBC"/>
            
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            dataSource>
        environment>
    environments>
    
configuration>

MyBatis从入门到精通_第5张图片

测试数据库连通性

@Test
public void testConetion() throws IOException {
    // 核心配置文件classpath路径
    String resource = "mybatis/mybatis-config.xml";
    // 加载配置文件
    Reader reader = Resources.getResourceAsReader(resource);
    // 构建会话工厂
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
    // 从SqlSessionFactory对象中获取SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    System.out.println(sqlSession.getConnection());
    // 归还连接给数据源
    sqlSession.close();
}

编写接口

com.lihaozhe.mapper.PersonMapper

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Person;

import java.util.List;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/6 上午8:52
 */
public interface PersonMapper {
    /**
     * 查询用户列表 resultType
     *
     * @return
     */
    List<Person> selectAll4t();
}

编写映射配置文件

src/main/java/com/lihaozhe/mapper/PersonMapper.xml

或者

src/main/resources/com/lihaozhe/mapper/PersonMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.lihaozhe.mapper.PersonMapper">
    

    
    <select id="selectAll4t" resultType="com.lihaozhe.pojo.Person">
        SELECT *
        FROM `person`
    select>
mapper>

MyBatis从入门到精通_第6张图片

核心配置文件加载映射配置文件


<mappers>
    
    
    
    
    
    
    
    <package name="com.lihaozhe.mapper"/>
mappers>

完整核心配置文件


DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    
    <properties resource="config.properties" />
    
    
    <environments default="development">
        
        <environment id="development">
            
            
            <transactionManager type="JDBC"/>
            
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            dataSource>
        environment>

    environments>
    <mappers>
        
        
        
        
        
        
        
        <package name="com.lihaozhe.mapper"/>
    mappers>

configuration>

测试

src/test/java/com/lihaozhe/mapper/PersonMapperTest.java

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Person;
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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

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

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/6 上午8:52
 */
public class PersonMapperTest {
    private SqlSession sqlSession;

    // JUnit5 @BeforeAll和@BeforeEach注解替换了 JUnit4 中的@Before注解。
    // 它⽤于表⽰应在当前类中的每个@Test⽅法之前执⾏注解⽅法。
    // 注意:@BeforeAll注解的⽅法必须为静态⽅法,否则它将引发运⾏时错误。
    // 注意:@BeforeEach注解的⽅法不得为静态⽅法,否则它将引发运⾏时错误。
    @BeforeEach
    public void openSqlSession() throws IOException {
        // 核心配置文件classpath路径
        String resource = "mybatis/mybatis-config.xml";
        // 加载配置文件
        Reader reader = Resources.getResourceAsReader(resource);
        // 构建会话工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        // 从SqlSessionFactory对象中获取SqlSession
        sqlSession = sqlSessionFactory.openSession();
    }

    @Test
    public void selectAll4t() {
        // 获取该接口的代理对象
        PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
        // 执行接口中的方法
        List<Person> people = mapper.selectAll4t();
        // 释放SqlSession资源
        sqlSession.close();
        // 遍历集合
        people.forEach(System.out::println);
    }
}

测试结果发现 idCard属性获取到的结果为null,

这是由于查询字段中没有idCard字段,

换言之 idCard属性 没有与 id_card字段形成映射关系

解决方法有两种:

  1. 使用ResultMap做结果集映射
  2. 在核心配置文件中设置 mapUnderscoreToCamelCase 值为 true

解决驼峰命名与下划线映射关系

使用 resultMap

映射配置文件中编写 resultMap



<resultMap id="PersonMap" type="com.lihaozhe.pojo.Person">
    
    <id property="id" column="id"/>
    <result property="id" column="id"/>
    <result property="uuid" column="uuid"/>
    <result property="mobile" column="mobile"/>
    <result property="nickname" column="nickname"/>
    <result property="idCard" column="id_card"/>
resultMap>

修改select id=“selectAll4m” 的属性 resultType=“com.lihaozhe.pojo.Person” 为 resultMap=“PersonMap”

<select id="selectAll4m" resultMap="PersonMap">
    SELECT *
    FROM `person`
select>

在接口中增加对应的方法

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Person;

import java.util.List;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午1:47
 */
public interface PersonMapper {
    /**
     * 查询用户列表 resultType
     *
     * @return
     */
    List<Person> selectAll4t();
    /**
     * 查询用户列表 resultMap
     *
     * @return
     */
    List<Person> selectAll4m();
}

测试 selectAll4m 方法

@Test
public void selectAll4m(){
    // 获取该接口的代理对象
    PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
    // 执行接口中的方法
    List<Person> people = mapper.selectAll4m();
    // 释放SqlSession资源
    sqlSession.close();
    // 遍历集合
    people.forEach(System.out::println);
}

配置 mapUnderscoreToCamelCase 值为 true

在核心配置文件中配置此参数如下

<settings>
    
    <setting name="mapUnderscoreToCamelCase" value="true"/>
settings>

测试 selectAll4t 方法

@Test
public void selectAll4t(){
    // 获取该接口的代理对象
    PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
    // 执行接口中的方法
    List<Person> people = mapper.selectAll4t();
    // 释放SqlSession资源
    sqlSession.close();
    // 遍历集合
    people.forEach(System.out::println);
}

在控制台显示log日志

在核心配置文件中 设置logImpl 的值为 STDOUT_LOGGING

<settings>
    
    <setting name="logImpl" value="STDOUT_LOGGING"/>
settings>

完整的核心配置文件

src/main/resources/mybatis/myatis-confog.xml


DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    
    <properties resource="config.properties" />
    <settings>
        
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    settings>
    
    
    <environments default="development">
        
        <environment id="development">
            
            
            <transactionManager type="JDBC"/>
            
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            dataSource>
        environment>

    environments>
    <mappers>
        
        
        
        
        
        
        
        <package name="com.lihaozhe.mapper"/>
    mappers>

configuration>

select

编写接口

com.lihaozhe.mapper.PersonMapper

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Person;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/6 上午8:52
 */
public interface PersonMapper {
    /**
     * 根据手机号查询用户信息
     * @param mobile
     * @return
     */
    Person selectByMobile(@Param("mobile") String mobile);
}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/PersonMapper.xml

默认情况下,使用 #{} 参数语法时,MyBatis 会创建 PreparedStatement 参数占位符,并通过占位符安全地设置参数(就像使用 ? 一样)。


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.PersonMapper">

    
    <select id="selectByMobile" parameterType="java.lang.String" resultType="com.lihaozhe.pojo.Person">
        SELECT *
        FROM `person`
		WHERE `mobile` = #{mobile}>
    select>

mapper>

MyBatis从入门到精通_第7张图片

测试类

com.lihaozhe.mapper.PersonMapperTest

注意:测试方法中获取SqlSession对象

@Test
public void selectByMobile(){
    // 获取该接口的代理对象
    PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
    // 执行接口中的方法
    Person person = mapper.selectByMobile("13925135946");
    // 释放SqlSession资源
    sqlSession.close();
    // 输出查询结果
    System.out.println(person);
}

#与$的区别

默认情况下,使用 #{} 参数语法时,MyBatis 会创建 PreparedStatement 参数占位符,并通过占位符安全地设置参数(就像使用 ? 一样)。

这样做更安全,更迅速,通常也是首选做法,不过有时你就是想直接在 SQL 语句中直接插入一个不转义的字符串。

比如 ORDER BY 子句,MyBatis 就不会修改或转义该字符串了。

需求:查询的条件字段和该字段的值不确定

编写接口

com.lihaozhe.mapper.PersonMapper

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Person;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/6 上午8:52
 */
public interface PersonMapper {
   /**
     * 根据不确定的字段查询
     * @param column
     * @param value
     * @return
     */
    Person selectByFiled(@Param("column") String column,@Param("value")String value);
}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/PersonMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.PersonMapper">

	
    <select id="selectByFiled" resultType="com.lihaozhe.pojo.Person">
        SELECT *
        FROM `person`
        WHERE ${column} = #{value}
    select>
mapper>

测试类

com.lihaozhe.mapper.PersonMapperTest

注意:测试方法中获取SqlSession对象

@Test
public void selectByFiled() {
    // 获取该接口的代理对象
    PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
    // 执行接口中的方法
    Person person = mapper.selectByFiled("mobile", "18400880850");
    // 释放SqlSession资源
    sqlSession.close();
    // 输出查询结果
    System.out.println(person);
}

解析结果:

==>  Preparing: SELECT `id`, `uuid`, `mobile`, `nickname`, `id_card` FROM `person` WHERE mobile = ?
==> Parameters: 18400880850(String)

MyBatis从入门到精通_第8张图片

别名映射

起因:parameterType 和 resultType 的值 需要使用类的完全限定名 太麻烦 希望使用 简短的名字来替代 类的完全限定名

在核心配置文件中 配置如下内容:

<typeAliases>
    
    
    <typeAlias alias="login" type="com.lihaozhe.pojo.Login"/>
typeAliases>

编写接口

com.lihaozhe.mapper.PersonMapper

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Login;
import org.apache.ibatis.annotations.Param;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 上午8:52
 */
public interface PersonMapper {
    /**
     * 根据唯一身份标识符用户信息
     *
     * @param uuid
     * @return
     */
    Person selectByUuid(@Param("uuid") String uuid);;
}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/PersonMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.PersonMapper">
    
    <select id="selectByUuid" resultType="person">
        SELECT *
        FROM `person`
        WHERE uuid = #{uuid}
    select>
mapper>

测试类

com.lihaozhe.mapper.PersonMapperTest

注意:测试方法中获取SqlSession对象

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Login;
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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.Reader;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/6 上午8:52
 */
public class LoginMapperTest {
    private SqlSession sqlSession;

    // JUnit5 @BeforeAll和@BeforeEach注解替换了 JUnit4 中的@Before注解。
    // 它⽤于表⽰应在当前类中的每个@Test⽅法之前执⾏注解⽅法。
    // 注意:@BeforeAll注解的⽅法必须为静态⽅法,否则它将引发运⾏时错误。
    // 注意:@BeforeEach注解的⽅法不得为静态⽅法,否则它将引发运⾏时错误。
    @BeforeEach
    public void openSqlSession() throws IOException {
        // 核心配置文件classpath路径
        String resource = "mybatis/mybatis-config.xml";
        // 加载配置文件
        Reader reader = Resources.getResourceAsReader(resource);
        // 构建会话工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        // 从SqlSessionFactory对象中获取SqlSession
        sqlSession = sqlSessionFactory.openSession();
    }
    @Test
    public void selectByPid(){
        LoginMapper mapper = sqlSession.getMapper(LoginMapper.class);
        Login login = mapper.selectByPid(3);
        sqlSession.close();
        System.out.println(login);
    }
}

某个包下所有类做别名映射

起因:在核心配置文件中单独为某个类做别名映射 如果需要映射的类太多 则过于麻烦 可以指定某个包面所有的类指定别名映射

<typeAliases>
    
    
    
    
    <package name="com.lihaozhe.pojo"/>
typeAliases>

完整核心配置文件

src/main/resources/mybatis/myatis-confog.xml


DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    
    <properties resource="config.properties" />
    <settings>
        
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    settings>
    <typeAliases>
        
        
        
        
        <package name="com.lihaozhe.pojo"/>
    typeAliases>
    
    
    <environments default="development">
        
        <environment id="development">
            
            
            <transactionManager type="JDBC"/>
            
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            dataSource>
        environment>

    environments>
    <mappers>
        
        
        
        
        
        
        
        <package name="com.lihaozhe.mapper"/>
    mappers>

configuration>

insert

编写接口

com.lihaozhe.mapper.DeptMapper

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Dept;
import org.apache.ibatis.annotations.Param;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/6 上午8:52
 */
public interface DeptMapper {
    /**
     * 新增部门
     *
     * @param dept
     * @return
     */
    int insert(@Param("dept") Dept dept);
}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/DeptMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.DeptMapper">
    
    <insert id="insert">
        INSERT INTO `dept` (`dname`)
        VALUES (#{dept.dname})
    insert>
mapper>

测试类

com.lihaozhe.mapper.DeptMapperTest

注意:测试方法中获取SqlSession对象

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Dept;
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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.Reader;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/6 上午8:52
 */
public class DeptMapperTest {
    private SqlSession sqlSession;

    // JUnit5 @BeforeAll和@BeforeEach注解替换了 JUnit4 中的@Before注解。
    // 它⽤于表⽰应在当前类中的每个@Test⽅法之前执⾏注解⽅法。
    // 注意:@BeforeAll注解的⽅法必须为静态⽅法,否则它将引发运⾏时错误。
    // 注意:@BeforeEach注解的⽅法不得为静态⽅法,否则它将引发运⾏时错误。
    @BeforeEach
    public void openSqlSession() throws IOException {
        // 核心配置文件classpath路径
        String resource = "mybatis/mybatis-config.xml";
        // 加载配置文件
        Reader reader = Resources.getResourceAsReader(resource);
        // 构建会话工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        // 从SqlSessionFactory对象中获取SqlSession
        sqlSession = sqlSessionFactory.openSession();
    }
    @Test
    public void insert(){
        // 获取代理对象
        DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
        // 准备数据
        Dept dept = new Dept("人事部");
        // 插入之前 输出准备数据
        System.out.println("插入之前 dept >>> " + dept);
        // 调用方法执行 insert 操作
        mapper.insert(dept);
        // 手动提交事务
        sqlSession.commit();
        // 释放资源
        sqlSession.close();
        // 插入之后 输出准备数据
        System.out.println("插入之后 dept >>> " + dept);
    }
}

解析结果:

插入之前 dept >>> Dept(did=0, dname=人事部)
Opening JDBC Connection
Created connection 671596011.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2807bdeb]
==>  Preparing: INSERT INTO `dept` (`dname`) VALUES (?)
==> Parameters: 人事部(String)
<==    Updates: 1
Committing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2807bdeb]
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2807bdeb]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2807bdeb]
Returned connection 671596011 to pool.
插入之后 dept >>> Dept(did=0, dname=人事部)

新增数据后获取新增数据主键值


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.DeptMapper">
    
    
    <insert id="insert" parameterType="dept" useGeneratedKeys="true" keyProperty="did" keyColumn="did">
        INSERT INTO `dept` (`dname`)
        VALUES (#{dept.dname})
    insert>
mapper>

解析结果:

插入之前 dept >>> Dept(did=0, dname=摸鱼部)
Opening JDBC Connection
Created connection 1643141512.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@61f05988]
==>  Preparing: INSERT INTO `dept` (`dname`) VALUES (?)
==> Parameters: 摸鱼部(String)
<==    Updates: 1
Committing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@61f05988]
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@61f05988]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@61f05988]
Returned connection 1643141512 to pool.
插入之后 dept >>> Dept(did=8, dname=摸鱼部)

update

编写接口

com.lihaozhe.mapper.DeptMappe

package com.lihaozhe.mapper;

import cn.hutool.core.collection.LineIter;
import com.lihaozhe.pojo.Dept;
import org.apache.ibatis.annotations.Param;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/6 上午8:52
 */
public interface DeptMapper {

    /**
     * 修改部门信息
     *
     * @param dept
     * @return
     */
    int update(@Param("dept") Dept dept);

}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/DeptMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.DeptMapper">
    
    <update id="update">
        UPDATE `dept`
        SET `dname` = #{dept.dname}
        WHERE `did` = #{dept.did}
    update>
mapper>

测试类

com.lihaozhe.mapper.DeptMappeTest

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Dept;
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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.Reader;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/6 上午8:52
 */
public class DeptMapperTest {
    private SqlSession sqlSession;

    // JUnit5 @BeforeAll和@BeforeEach注解替换了 JUnit4 中的@Before注解。
    // 它⽤于表⽰应在当前类中的每个@Test⽅法之前执⾏注解⽅法。
    // 注意:@BeforeAll注解的⽅法必须为静态⽅法,否则它将引发运⾏时错误。
    // 注意:@BeforeEach注解的⽅法不得为静态⽅法,否则它将引发运⾏时错误。
    @BeforeEach
    public void getSqlSession() throws IOException {
        // 核心配置文件classpath路径
        String resource = "mybatis/mybatis-config.xml";
        // 加载配置文件
        Reader reader = Resources.getResourceAsReader(resource);
        // 构建会话工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        // 从SqlSessionFactory对象中获取SqlSession
        sqlSession = sqlSessionFactory.openSession();
    }
    @Test
    public void update() {
        // 获取代理对象
        DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
        // 准备数据
        Dept dept = new Dept(8, "企宣部");
        // 调用方法执行 update 操作
        mapper.update(dept);
        // 手动提交事务
        sqlSession.commit();
        // 释放资源
        sqlSession.close();
    }
}

delete

编写接口

com.lihaozhe.mapper.DeptMappe

package com.lihaozhe.mapper;

import cn.hutool.core.collection.LineIter;
import com.lihaozhe.pojo.Dept;
import org.apache.ibatis.annotations.Param;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/6 上午11:13
 */
public interface DeptMapper {

    /**
     * 根据部门id删除部门
     *
     * @param did
     * @return
     */
    int deleteByDid(@Param("did") long did);

}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/DeptMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.DeptMapper">
   
   <delete id="deleteByDid">
        DELETE
        FROM `dept`
        WHERE `did` = #{did}
    delete>
mapper>

测试类

com.lihaozhe.mapper.DeptMappeTest

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Dept;
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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.Reader;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午3:56
 */
public class DeptMapperTest {
    private SqlSession sqlSession;

    // JUnit5 @BeforeAll和@BeforeEach注解替换了 JUnit4 中的@Before注解。
    // 它⽤于表⽰应在当前类中的每个@Test⽅法之前执⾏注解⽅法。
    // 注意:@BeforeAll注解的⽅法必须为静态⽅法,否则它将引发运⾏时错误。
    // 注意:@BeforeEach注解的⽅法不得为静态⽅法,否则它将引发运⾏时错误。
    @BeforeEach
    public void getSqlSession() throws IOException {
        // 核心配置文件classpath路径
        String resource = "mybatis/mybatis-config.xml";
        // 加载配置文件
        Reader reader = Resources.getResourceAsReader(resource);
        // 构建会话工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        // 从SqlSessionFactory对象中获取SqlSession
        sqlSession = sqlSessionFactory.openSession();
    }

    @Test
    public void deleteByDid(){
        // 获取代理对象
        DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
        // 调用方法执行 delete 操作
        mapper.deleteByDid(8);
        // 手动提交事务
        sqlSession.commit();
        // 释放资源
        sqlSession.close();
    }
}

工具类

com.lihaozhe.util.mybatis.MyBatisUtil

package com.lihaozhe.util.mybatis;

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

import java.io.IOException;
import java.io.Reader;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/13 上午11:39
 */
public abstract class MyBatisUtil {
    private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<>();
    private static SqlSessionFactory sqlSessionFactory;
    private static SqlSession sqlSession;

    static {
        // 核心配置文件classpath路径
        String resource = "mybatis/mybatis-config.xml";
        // 加载配置文件
        Reader reader = null;
        try {
            reader = Resources.getResourceAsReader(resource);
            // 构建会话工厂
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 获取 SqlSession 对象
     *
     * @return SqlSession 对象
     */
    public static SqlSession openSqlSession() {
        if (threadLocal.get() == null) {
            // 从SqlSessionFactory对象中获取SqlSession
            sqlSession = sqlSessionFactory.openSession();
            // 与线程绑定
            threadLocal.set(sqlSession);
            // 返回 SqlSession 对象
            return sqlSession;
        } else {
            return threadLocal.get();
        }
    }

    /**
     * 获取 SqlSession 对象
     *
     * @param executorType SIMPLE,REUSE,BATCH
     * @return SqlSession 对象
     */
    public static SqlSession openSqlSession(ExecutorType executorType) {
        if (threadLocal.get() == null) {
            // 从SqlSessionFactory对象中获取SqlSession
            sqlSession = sqlSessionFactory.openSession(executorType);
            // 与线程绑定
            threadLocal.set(sqlSession);
            // 返回 SqlSession 对象
            return sqlSession;
        } else {
            return threadLocal.get();
        }
    }

    /**
     * 释放资源
     */
    public static void close() {
        if (threadLocal.get() != null) {
            sqlSession = threadLocal.get();
            threadLocal.remove();
            sqlSession.close();
        }
    }

    /**
     * 事务提交 释放资源
     */
    public static void commitAndClose() {
        if (threadLocal.get() != null) {
            sqlSession = threadLocal.get();
            threadLocal.remove();
            sqlSession.commit();
            sqlSession.close();
        }
    }

    /**
     * 事务回滚 释放资源
     */
    public static void rollbackAndClose() {
        if (threadLocal.get() != null) {
            sqlSession = threadLocal.get();
            threadLocal.remove();
            sqlSession.rollback();
            sqlSession.close();
        }
    }
}

动态SQL

MyBatis从入门到精通_第9张图片

@Test
public void test() {
    // 需求:查询某部门的(did)  名字有某个字的(ename) 员工列表
    // 分析:
    // 如果不给部门编号则在所有部门中查找 did  不能为 0
    // 如果有部门编号则在某部门内查找
    long did = 3;
    StringBuilder sql = new StringBuilder("select * from person where ");
    if (did != 0) {
        sql.append(" did = ?");
        sql.append(" and ename like ");
        sql.append(" '%");
        sql.append(" ? ");
        sql.append("%' ");
    }else {
        sql.append(" ename like ");
        sql.append(" '%");
        sql.append(" ? ");
        sql.append("%' ");
    }
    System.out.println(sql.toString());
    // select * from person where  ename like  %  ?  % 
    // select * from person where  did = ? and ename like  %  ?  % 
}

起因:根据不同的查询条件生成不同的SQL语句

sql片段

将经常使用的SQL语句定义成SQL片段当使用的时候引导该片段即可 有点像 变量的赋值与引用

编写接口

com.lihaozhe.mapper.PersonMapper

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Person;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午1:47
 */
public interface PersonMapper {
    /**
     * 根据用户ID查询该用户信息 使用SQL片段
     *
     * @return
     */
    Person selectById(@Param("id") long id);
}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/PersonMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.PersonMapper">
    
    <sql id="select_person">
        SELECT *
        FROM `person`
    sql>
    
    <select id="selectById" resultType="person">
        <include refid="select_person">include>
        WHERE `id` = #{id}
    select>
mapper>

编写测试类

com.lihaozhe.mapper.PersonMapperTest

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Person;
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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

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

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午1:51
 */
public class PersonMapperTest {
    private SqlSession sqlSession;

    // JUnit5 @BeforeAll和@BeforeEach注解替换了 JUnit4 中的@Before注解。
    // 它⽤于表⽰应在当前类中的每个@Test⽅法之前执⾏注解⽅法。
    // 注意:@BeforeAll注解的⽅法必须为静态⽅法,否则它将引发运⾏时错误。
    // 注意:@BeforeEach注解的⽅法不得为静态⽅法,否则它将引发运⾏时错误。
    @BeforeEach
    public void openSqlSession() throws IOException {
        // 核心配置文件classpath路径
        String resource = "mybatis/mybatis-config.xml";
        // 加载配置文件
        Reader reader = Resources.getResourceAsReader(resource);
        // 构建会话工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        // 从SqlSessionFactory对象中获取SqlSession
        sqlSession = sqlSessionFactory.openSession();
    }
    
    @Test
    public void selectById() {
        // 获取该接口的代理对象
        PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
        // 执行接口中的方法
        Person person = mapper.selectByid(3);
        // 释放SqlSession资源
        sqlSession.close();
        // 输出查询结果
        System.out.println(person);
    }
}

SQL解析结果:

==>  Preparing: SELECT `id`, `uuid`, `mobile`, `nickname`, `id_card` FROM `person` WHERE `id` = ?
==> Parameters: 3(Long)
<==    Columns: id, uuid, mobile, nickname, id_card
<==        Row: 3, 5bc69d3c6aba4a61a81115ba916237f3, 13925135946, 邹庶, 313227198110042264
<==      Total: 1

MyBatis从入门到精通_第10张图片

bind

编写接口

com.lihaozhe.mapper.PersonMapper

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Person;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午1:47
 */
public interface PersonMapper {

    /**
     * 模糊查找某姓名中包含某个字的用户
     *
     * @param nickname
     * @return
     */
    List<Person> selectByNickname(@Param("nickname") String nickname);
}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/PersonMapper.xml


<sql id="select_person">
    SELECT *
    FROM `person`
sql>


<select id="selectByNickname" resultType="person">
    
    <select id="selectByNickname" resultType="person">
        <bind name="like_nickname" value="'%' + nickname + '%'"/>
        <include refid="select_person">include>
        WHERE `nickname` like #{like_nickname}
    select>
select>

注意:在bind标签中value属性获取值的时候不需要使用#

编写测试类

com.lihaozhe.mapper.PersonMapperTest

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Person;
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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

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

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午1:51
 */
public class PersonMapperTest {
    private SqlSession sqlSession;

    // JUnit5 @BeforeAll和@BeforeEach注解替换了 JUnit4 中的@Before注解。
    // 它⽤于表⽰应在当前类中的每个@Test⽅法之前执⾏注解⽅法。
    // 注意:@BeforeAll注解的⽅法必须为静态⽅法,否则它将引发运⾏时错误。
    // 注意:@BeforeEach注解的⽅法不得为静态⽅法,否则它将引发运⾏时错误。
    @BeforeEach
    public void getSqlSession() throws IOException {
        // 核心配置文件classpath路径
        String resource = "mybatis/mybatis-config.xml";
        // 加载配置文件
        Reader reader = Resources.getResourceAsReader(resource);
        // 构建会话工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        // 从SqlSessionFactory对象中获取SqlSession
        sqlSession = sqlSessionFactory.openSession();
    }

    @Test
    public void selectByNickname() {
        // 获取接口代理对象
        PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
        // 准备数据集
        String nickname = "孙";
        // %孙%
        StringBuilder param = new StringBuilder();
        param.append("%");
        if (!StringUtils.isEmpty(nickname)) {
            param.append(nickname);
        }
        param.append("%");
        // 执行代理对象中的方法
        List<Person> personList = mapper.selectByNickname(param.toString());
        // 释放资源
        sqlSession.close();
        // 输出结果
        personList.forEach(System.out::println);
    }
}

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Person;
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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

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

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午1:51
 */
public class PersonMapperTest {
    private SqlSession sqlSession;

    // JUnit5 @BeforeAll和@BeforeEach注解替换了 JUnit4 中的@Before注解。
    // 它⽤于表⽰应在当前类中的每个@Test⽅法之前执⾏注解⽅法。
    // 注意:@BeforeAll注解的⽅法必须为静态⽅法,否则它将引发运⾏时错误。
    // 注意:@BeforeEach注解的⽅法不得为静态⽅法,否则它将引发运⾏时错误。
    @BeforeEach
    public void getSqlSession() throws IOException {
        // 核心配置文件classpath路径
        String resource = "mybatis/mybatis-config.xml";
        // 加载配置文件
        Reader reader = Resources.getResourceAsReader(resource);
        // 构建会话工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        // 从SqlSessionFactory对象中获取SqlSession
        sqlSession = sqlSessionFactory.openSession();
    }

    @Test
    public void selectByNickname() {
       // 获取接口代理对象
        PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
        // 执行代理对象中的方法
        List<Person> personList = mapper.selectByNickname("孙");
        // 释放资源
        sqlSession.close();
        // 输出结果
        personList.forEach(System.out::println);
    }
}

结果解析:

==>  Preparing: SELECT `id`, `uuid`, `mobile`, `nickname`, `id_card` FROM `person` WHERE `nickname` LIKE ?
==> Parameters: %孙%(String)
<==    Columns: id, uuid, mobile, nickname, id_card
<==        Row: 2, 82bbfb207b38447e93fffe3c53ba3e5b, 15051340785, 孙陈, 919948197901282822
<==        Row: 31, 3db353f3b81b44c6bc6095487d8a5b05, 13628389232, 孙鹃祈, 314211197412052754
<==        Row: 72, 2032a25e5245454894e192d8d5b17147, 13352587230, 孙茎, 453355198107241539
<==      Total: 3

if

编写接口

com.lihaozhe.mapper.PersonMapper

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Person;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午1:47
 */
public interface PersonMapper {
    
    /**
     * 模糊查找某姓名中包含某个字的男性或女性用户
     *
     * @param nickname
     * @return
     */
    List<Person> selectByGenderAndNickname(@Param("gender") Integer gender, @Param("nickname") String nickname);
}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/PersonMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.PersonMapper">
    
    <sql id="select_person">
        SELECT *
        FROM `person`
    sql>
    
    <select id="selectByGenderAndNickname" resultType="person">
        <include refid="select_person">include>
        WHERE
        <if test="gender != null">
            if(mod(substr(id_card, 17, 1), 2), 1, 0) = #{gender}
        if>
        <if test="nickname != null and nickname.length > 0">
            <bind name="like_nickname" value="'%' + nickname + '%'"/>
            AND `nickname` like #{like_nickname}
        if>
    select>
mapper>

结果解析:

-- 当方法中参数nickname的值为null或者字符串长度为零
SELECT `id`, `uuid`, `mobile`, `nickname`, `id_card` FROM `person` WHERE `gender` = ?
-- 当方法中参数nickname的值不为null且字符串长度大于零
SELECT `id`, `uuid`, `mobile`, `nickname`, `id_card` FROM `person` WHERE `gender` = ? AND `nickname` LIKE ?

编写测试类

com.lihaozhe.mapper.PersonMapperTest

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Person;
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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

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

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午1:51
 */
public class PersonMapperTest {
    private SqlSession sqlSession;

    // JUnit5 @BeforeAll和@BeforeEach注解替换了 JUnit4 中的@Before注解。
    // 它⽤于表⽰应在当前类中的每个@Test⽅法之前执⾏注解⽅法。
    // 注意:@BeforeAll注解的⽅法必须为静态⽅法,否则它将引发运⾏时错误。
    // 注意:@BeforeEach注解的⽅法不得为静态⽅法,否则它将引发运⾏时错误。
    @BeforeEach
    public void oepnSqlSession() throws IOException {
        // 核心配置文件classpath路径
        String resource = "mybatis/mybatis-config.xml";
        // 加载配置文件
        Reader reader = Resources.getResourceAsReader(resource);
        // 构建会话工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        // 从SqlSessionFactory对象中获取SqlSession
        sqlSession = sqlSessionFactory.openSession();
    }

    @Test
    public void selectByGenderAndNickname() {
        // 获取接口代理对象
        PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
        // 执行代理对象中的方法
        // List personList = mapper.selectByGenderAndNickname(0,null);
           List<Person> personList = mapper.selectByGenderAndNickname(1,"孙");
        // 释放资源
        sqlSession.close();
        // 输出结果
        personList.forEach(System.out::println);
    }
}

where

使用上面if相同的方法selectByGenderAndNickname和配置文件

当两个参数同时为null的时候sql语句为 :

SELECT * FROM `perason` WHERE 

这条sql语句存在语法错误 当没有查询条件的时候做出如下配置


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.PersonMapper">
    
    <sql id="select_person">
        SELECT *
        FROM `person`
    sql>
    
    <select id="selectByGenderAndNickname" resultType="person">
        <include refid="select_person">include>
        WHERE
        <if test="gender != null">
            if(mod(substr(id_card, 17, 1), 2), 1, 0) = #{gender}
        if>
        <if test="nickname != null and nickname.length > 0">
            <bind name="like_nickname" value="'%' + nickname + '%'"/>
            AND `nickname` like #{like_nickname}
        if>
    select>
mapper>

choose (when, otherwise)

有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。

需求:id, uuid, mobile 多个查询条件选择其中一个

编写接口

com.lihaozhe.mapper.PersonMapper

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Person;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午1:47
 */
public interface PersonMapper {

    /**
     * `id`, `uuid`, `mobile` 多个查询条件选择其中一个
     * @param person
     * @return
     */
    Person selectByIdOrUuidOrMobile(@Param("person") Person person);
}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/PersonMapper.xml


<sql id="select_person">
    SELECT *
    FROM `person`
sql>

<select id="selectByIdOrUuidOrMobile" resultType="person">
    <include refid="select_person">include>
    <where>
        <choose>
            <when test="person.id != null and person.id > 0">
                `id` = #{person.id}
            when>
            <when test="person.uuid != null and person.uuid.length > 0">
                `uuid` = #{person.uuid}
            when>
            <otherwise>
                `mobile` = #{person.mobile}
            otherwise>
        choose>
    where>
select>

解析结果:

-- 只传入mobile
SELECT `id`, `uuid`, `mobile`, `nickname`, `id_card` FROM `person` WHERE `mobile` = ?
-- 传入uuid
SELECT `id`, `uuid`, `mobile`, `nickname`, `id_card` FROM `person` WHERE `uuid` = ?
-- 传入id
SELECT `id`, `uuid`, `mobile`, `nickname`, `id_card` FROM `person` WHERE `id` = ?

编写测试类

com.lihaozhe.mapper.PersonMapperTest

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Person;
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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

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

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午1:51
 */
public class PersonMapperTest {
    private SqlSession sqlSession;

    // JUnit5 @BeforeAll和@BeforeEach注解替换了 JUnit4 中的@Before注解。
    // 它⽤于表⽰应在当前类中的每个@Test⽅法之前执⾏注解⽅法。
    // 注意:@BeforeAll注解的⽅法必须为静态⽅法,否则它将引发运⾏时错误。
    // 注意:@BeforeEach注解的⽅法不得为静态⽅法,否则它将引发运⾏时错误。
    @BeforeEach
    public void openSqlSession() throws IOException {
        // 核心配置文件classpath路径
        String resource = "mybatis/mybatis-config.xml";
        // 加载配置文件
        Reader reader = Resources.getResourceAsReader(resource);
        // 构建会话工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        // 从SqlSessionFactory对象中获取SqlSession
        sqlSession = sqlSessionFactory.openSession();
    }

    @Test
    public void selectByIdOrUuidOrMobile() {
        // 获取该接口的代理对象
        PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
        // 准备数据
        Person person = new Person();
        // SELECT `id`, `uuid`, `mobile`, `nickname`, `id_card` FROM `person` WHERE `mobile` = ?
        person.setMobile("13352587230");

        // SELECT `id`, `uuid`, `mobile`, `nickname`, `id_card` FROM `person` WHERE `uuid` = ?
		person.setUuid("2032a25e5245454894e192d8d5b17147");

        // SELECT `id`, `uuid`, `mobile`, `nickname`, `id_card` FROM `person` WHERE `id` = ?
        person.setId(33);

        // 执行接口中的方法
        person = mapper.selectByIdOrUuidOrMobile(person);
        // SELECT `id`, `uuid`, `mobile`, `nickname`, `id_card` FROM `person` WHERE `nickname` LIKE ?
        // 释放SqlSession资源
        sqlSession.close();
        // 输出查询结果
        System.out.println(person);
    }
}

trim

编写接口

com.lihaozhe.mapper.EmpMapper

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Emp;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/8 上午10:32
 */
public interface EmpMapper {
    /**
     * 动态SQL if 按照部门ID和姓名中部分关键字查找
     * 如果没有传递部门ID则在所有部门中查找
     * 如果传递部门ID但没有传递姓名中的关键字则查找该部门下所有员工列表
     * 如果部门ID和姓名中的关键字都没有传递则查找所有员工列表
     *
     * @param emp
     * @return
     */
    List<Emp> selcetByDidAndEname(@Param("emp") Emp emp);
}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/EmpMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.EmpMapper">
    
    <select id="selectByDidAndEname" resultType="emp">
        SELECT * FROM `emp`
        <trim prefix="where" prefixOverrides="AND|OR">
            <if test="emp.did != null and emp.did > 0">
                `did` = #{emp.did}
            if>
            <if test="emp.ename != null and emp.ename.length > 0">
                <bind name="like_ename" value="'%' + emp.ename + '%'"/>
                AND `ename` like #{like_ename}
            if>
        trim>
    select>
mapper>

解析 结果:

-- ename 孙
SELECT `eid`, `ename`, `did` FROM `emp` WHERE `ename` Like ?

-- ename ""
SELECT `eid`, `ename`, `did` FROM `emp`

-- did 3
SELECT `eid`, `ename`, `did` FROM `emp` WHERE `did` = ?

-- did 3 并且 ename 孙
SELECT `eid`, `ename`, `did` FROM `emp` WHERE `did` = ? AND `ename` Like ?

编写测试类

com.lihaozhe.mapper.EmpMapperTest

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Emp;
import com.lihaozhe.util.mybatis.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

import java.util.List;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/8 下午12:02
 */
public class EmpMapperTest {
    @Test
    public void selcetByDidAndEname(){
        // 使用工具类获取 SqlSession 对象
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        // 获取接口代理对象
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        // 准备数据
        Emp emp = new Emp();
        // SELECT `eid`, `ename`, `did` FROM `emp` WHERE `ename` Like ?
        emp.setEname("孙");

        // SELECT `eid`, `ename`, `did` FROM `emp`
        // emp.setEname("");

        // SELECT `eid`, `ename`, `did` FROM `emp` WHERE `did` = ?
        emp.setDid(3);
        // SELECT `eid`, `ename`, `did` FROM `emp` WHERE `did` = ? AND `ename` Like ?
        // 执行 接口 中的方法
        List<Emp> emps = mapper.selcetByDidAndEname(emp);
        // 使用工具类 释放资源
        MyBatisUtil.close();
        // 输出结果
        emps.forEach(System.out::println);
    }
}

set

用于动态更新语句的类似解决方案叫做 set, set 元素可以用于动态包含需要更新的列,忽略其它不更新的列。

需求:更新 person表 中的个别字段

编写接口

com.lihaozhe.mapper.PersonMapper

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Person;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午1:47
 */
public interface PersonMapper {
    
    /**
     * 修改员工表数据
     *
     * @param person
     * @return
     */
    int updateById(@Param("person") Person person);
}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/PersonMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.PersonMapper">
    
    <update id="updateById" parameterType="person">
        UPDATE `person`
        <set>
            <if test="person.nickname != null and person.nickname.length > 0">
                `nickname` = #{person.nickname},
            if>
            <if test="person.mobile != null and person.mobile.length == 11">
                `mobile` = #{person.mobile},
            if>
            <if test="person.idCard != null and (person.idCard.length == 18 or person.idCard.length == 15)">
                `id_card` = #{person.idCard}
            if>
        set>
        WHERE `id` = #{person.id}
    update>

mapper>

或者:


<update id="updateById">
    UPDATE `person`
    <trim prefix="set" suffixOverrides=",">
        <if test="person.nickname != null and person.nickname.length > 0">
            `nickname` = #{person.nickname},
        if>
        <if test="person.mobile != null and person.mobile.length == 11">
            `mobile` = #{person.mobile},
        if>
        <if test="person.idCard != null and (person.idCard.length == 18 or person.idCard.length == 15)">
            `id_card` = #{person.idCard}
        if>
    trim>
    WHERE `id` = #{person.id}
update>

编写测试类

com.lihaozhe.mapper.PersonMapperTest

package com.lihaozhe.mapper;

import cn.binarywang.tools.generator.ChineseIDCardNumberGenerator;
import cn.binarywang.tools.generator.ChineseMobileNumberGenerator;
import cn.binarywang.tools.generator.ChineseNameGenerator;
import cn.hutool.core.util.IdUtil;
import com.lihaozhe.pojo.Person;
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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

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

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午1:51
 */
public class PersonMapperTest {
    private SqlSession sqlSession;

    // JUnit5 @BeforeAll和@BeforeEach注解替换了 JUnit4 中的@Before注解。
    // 它⽤于表⽰应在当前类中的每个@Test⽅法之前执⾏注解⽅法。
    // 注意:@BeforeAll注解的⽅法必须为静态⽅法,否则它将引发运⾏时错误。
    // 注意:@BeforeEach注解的⽅法不得为静态⽅法,否则它将引发运⾏时错误。
    @BeforeEach
    public void openSqlSession() throws IOException {
        // 核心配置文件classpath路径
        String resource = "mybatis/mybatis-config.xml";
        // 加载配置文件
        Reader reader = Resources.getResourceAsReader(resource);
        // 构建会话工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        // 从SqlSessionFactory对象中获取SqlSession
        sqlSession = sqlSessionFactory.openSession();
    }

    @Test
    public void updateById() {
        // 获取该接口的代理对象
        PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
        // 准备数据
        Person person = new Person();
        String mobile = ChineseMobileNumberGenerator.getInstance().generate();
        System.out.println(mobile);
        // UPDATE `person` SET `mobile` = ? WHERE `id` = ?
        person.setMobile(mobile);
        person.setId(3);

        // 执行接口中的方法
        mapper.updateById(person);
        // 事务提交
        sqlSession.commit();
        // 释放SqlSession资源
        sqlSession.close();
        // 输出结果
        if (status > 0) {
            System.out.println("☺");
        } else {
            System.out.println("o(╯□╰)o");
        }
    }

}

foreach

select

编写接口

com.lihaozhe.mapper.PersonMapper

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Person;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午1:47
 */
public interface PersonMapper {

    /**
     * 查找多个id的用户列表
     *
     * @param ids
     * @return
     */
    List<Person> selectByIds(@Param("ids") Long... ids);

}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/PersonMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.PersonMapper">
	 
    <sql id="select_person">
        SELECT *
        FROM `person`
    sql>
    
    <select id="selectByIds" resultType="person">
        <include refid="select_person">include>
        <where>
            `id` IN
            <foreach collection="ids" index="index" item="id" open="(" separator="," close=")">
                #{id}
            foreach>
        where>
    select>
mapper>
编写测试类

com.lihaozhe.mapper.PersonMapper

package com.lihaozhe.mapper;

import cn.binarywang.tools.generator.ChineseIDCardNumberGenerator;
import cn.binarywang.tools.generator.ChineseMobileNumberGenerator;
import cn.binarywang.tools.generator.ChineseNameGenerator;
import cn.hutool.core.util.IdUtil;
import com.lihaozhe.pojo.Person;
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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

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

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午1:51
 */
public class PersonMapperTest {
    private SqlSession sqlSession;

    // JUnit5 @BeforeAll和@BeforeEach注解替换了 JUnit4 中的@Before注解。
    // 它⽤于表⽰应在当前类中的每个@Test⽅法之前执⾏注解⽅法。
    // 注意:@BeforeAll注解的⽅法必须为静态⽅法,否则它将引发运⾏时错误。
    // 注意:@BeforeEach注解的⽅法不得为静态⽅法,否则它将引发运⾏时错误。
    @BeforeEach
    public void openSqlSession() throws IOException {
        // 核心配置文件classpath路径
        String resource = "mybatis/mybatis-config.xml";
        // 加载配置文件
        Reader reader = Resources.getResourceAsReader(resource);
        // 构建会话工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        // 从SqlSessionFactory对象中获取SqlSession
        sqlSession = sqlSessionFactory.openSession();
    }

    @Test
    public void selectByIds() {
        // 获取该接口的代理对象
        PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
        // 执行接口中的方法
        List<Person> personList = mapper.selectByIds(1L, 3L, 5L);
        // 释放SqlSession资源
        sqlSession.close();
        // 输出查询结果
        personList.forEach(System.out::println);
    }
}

delete

编写接口

com.lihaozhe.mapper.PersonMapper

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Person;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午1:47
 */
public interface PersonMapper {
  
    /**
     * 根据传入的id删除用户
     *
     * @param ids
     * @return
     */
    int delByIds(@Param("ids") Long... ids);

}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/PersonMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.PersonMapper">

    
    <delete id="delByIds">
        DELETE FROM `person`
        <where>
            `id` IN
            <foreach collection="ids" index="index" item="id" open="(" separator="," close=")">
                #{id}
            foreach>
        where>
    delete>
mapper>
编写测试类

com.lihaozhe.mapper.PersonMapper

package com.lihaozhe.mapper;

import cn.binarywang.tools.generator.ChineseIDCardNumberGenerator;
import cn.binarywang.tools.generator.ChineseMobileNumberGenerator;
import cn.binarywang.tools.generator.ChineseNameGenerator;
import cn.hutool.core.util.IdUtil;
import com.lihaozhe.pojo.Person;
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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

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

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午1:51
 */
public class PersonMapperTest {
    private SqlSession sqlSession;

    // JUnit5 @BeforeAll和@BeforeEach注解替换了 JUnit4 中的@Before注解。
    // 它⽤于表⽰应在当前类中的每个@Test⽅法之前执⾏注解⽅法。
    // 注意:@BeforeAll注解的⽅法必须为静态⽅法,否则它将引发运⾏时错误。
    // 注意:@BeforeEach注解的⽅法不得为静态⽅法,否则它将引发运⾏时错误。
    @BeforeEach
    public void openSqlSession() throws IOException {
        // 核心配置文件classpath路径
        String resource = "mybatis/mybatis-config.xml";
        // 加载配置文件
        Reader reader = Resources.getResourceAsReader(resource);
        // 构建会话工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        // 从SqlSessionFactory对象中获取SqlSession
        sqlSession = sqlSessionFactory.openSession();
    }

    @Test
    public void delByIds() {
        // 获取该接口的代理对象
        PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
        // 执行接口中的方法
        mapper.delByIds(1L, 3L, 5L);
        // 事务提交
        sqlSession.commit();
        // 释放SqlSession资源
        sqlSession.close();
        // 输出结果
        if (status > 0) {
            System.out.println("☺");
            System.out.println(status + " 条记录被删除");
        } else {
            System.out.println("o(╯□╰)o");
        }
    }
}

insert

清空person表

truncate person;
编写接口

com.lihaozhe.mapper.PersonMapper

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Person;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午1:47
 */
public interface PersonMapper {

    /**
     * 新增用户列列表
     *
     * @param personList
     * @return
     */
    int insertAll(@Param("personList") List<Person> personList);
}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/PersonMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.PersonMapper">

    
    <insert id="insertAll">
        INSERT INTO `person` (`uuid`,`mobile`,`nickname`,`id_card`) VALUES
        <foreach collection="personList" index="index" item="person" separator=",">
            (#{person.uuid},#{person.mobile},#{person.nickname},#{person.idCard})
        foreach>
    insert>
mapper>
编写测试类

com.lihaozhe.mapper.PersonMapper

package com.lihaozhe.mapper;

import cn.binarywang.tools.generator.ChineseIDCardNumberGenerator;
import cn.binarywang.tools.generator.ChineseMobileNumberGenerator;
import cn.binarywang.tools.generator.ChineseNameGenerator;
import cn.hutool.core.util.IdUtil;
import com.lihaozhe.pojo.Person;
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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

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

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午1:51
 */
public class PersonMapperTest {
    private SqlSession sqlSession;

    // JUnit5 @BeforeAll和@BeforeEach注解替换了 JUnit4 中的@Before注解。
    // 它⽤于表⽰应在当前类中的每个@Test⽅法之前执⾏注解⽅法。
    // 注意:@BeforeAll注解的⽅法必须为静态⽅法,否则它将引发运⾏时错误。
    // 注意:@BeforeEach注解的⽅法不得为静态⽅法,否则它将引发运⾏时错误。
    @BeforeEach
    public void openSqlSession() throws IOException {
        // 核心配置文件classpath路径
        String resource = "mybatis/mybatis-config.xml";
        // 加载配置文件
        Reader reader = Resources.getResourceAsReader(resource);
        // 构建会话工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        // 从SqlSessionFactory对象中获取SqlSession
        sqlSession = sqlSessionFactory.openSession();
    }

    @Test
    public void insertAll() {
        // 准备数据
        ArrayList<Person> personList = new ArrayList<>();
        for (int i = 0; i < 200; i++) {
            Person person = new Person();
            person.setUuid(IdUtil.fastSimpleUUID());
            person.setMobile(ChineseMobileNumberGenerator.getInstance().generate());
            person.setNickname(ChineseNameGenerator.getInstance().generate());
            person.setIdCard(ChineseIDCardNumberGenerator.getInstance().generate());
            System.out.println(person);
            personList.add(person);
        }
        // 获取接口代理对象
        PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
        // 执行代理对象中的方法
        int status = mapper.insertAll(personList);
        // 事务提交
        sqlSession.commit();
        // 释放资源
        sqlSession.close();

        // 输出结果
        if (status > 0) {
            System.out.println("☺");
            System.out.println("新增了 " + status + " 条记录");
        } else {
            System.out.println("o(╯□╰)o");
        }
    }
}

性能

@Test
public void testConetion() throws IOException {
    // 核心配置文件classpath路径
    String resource = "mybatis/mybatis-config.xml";
    // 加载配置文件
    Reader reader = Resources.getResourceAsReader(resource);
    // 构建会话工厂
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
    // 从SqlSessionFactory对象中获取SqlSession 同时设置批处理
    SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
    System.out.println(sqlSession.getConnection());
    // 归还连接给数据源
    sqlSession.close();
}

工具类修改

package com.lihaozhe.util.mybatis;

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

import java.io.IOException;
import java.io.Reader;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/13 上午11:39
 */
public abstract class MyBatisUtil {
    private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<>();
    private static SqlSessionFactory sqlSessionFactory;
    private static SqlSession sqlSession;

    static {
        // 核心配置文件classpath路径
        String resource = "mybatis/mybatis-config.xml";
        // 加载配置文件
        Reader reader = null;
        try {
            reader = Resources.getResourceAsReader(resource);
            // 构建会话工厂
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 获取 SqlSession 对象
     *
     * @return SqlSession 对象
     */
    public static SqlSession openSqlSession() {
        if (threadLocal.get() == null) {
            // 从SqlSessionFactory对象中获取SqlSession
            sqlSession = sqlSessionFactory.openSession();
            // 与线程绑定
            threadLocal.set(sqlSession);
            // 返回 SqlSession 对象
            return sqlSession;
        } else {
            return threadLocal.get();
        }
    }

    /**
     * 获取 SqlSession 对象
     *
     * @param executorType SIMPLE,REUSE,BATCH
     * @return SqlSession 对象
     */
    public static SqlSession openSqlSession(ExecutorType executorType) {
        if (threadLocal.get() == null) {
            // 从SqlSessionFactory对象中获取SqlSession
            sqlSession = sqlSessionFactory.openSession(executorType);
            // 与线程绑定
            threadLocal.set(sqlSession);
            // 返回 SqlSession 对象
            return sqlSession;
        } else {
            return threadLocal.get();
        }
    }

    /**
     * 释放资源
     */
    public static void close() {
        if (threadLocal.get() != null) {
            sqlSession = threadLocal.get();
            threadLocal.remove();
            sqlSession.close();
        }
    }

    /**
     * 事务提交 释放资源
     */
    public static void commitAndClose() {
        if (threadLocal.get() != null) {
            sqlSession = threadLocal.get();
            threadLocal.remove();
            sqlSession.commit();
            sqlSession.close();
        }
    }

    /**
     * 事务回滚 释放资源
     */
    public static void rollbackAndClose() {
        if (threadLocal.get() != null) {
            sqlSession = threadLocal.get();
            threadLocal.remove();
            sqlSession.rollback();
            sqlSession.close();
        }
    }
}

select

一对一

resultType

编写接口

com.lihaozhe.mapper.LoginMapper

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Login;
import com.lihaozhe.pojo.Person;
import org.apache.ibatis.annotations.Param;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午3:27
 */
public interface LoginMapper {

    /**
     * 使用账号和密码登录 获取用户信息
     *
     * @param login 登录参数 account password
     * @return
     */
    Person selectPersonByAccountAndPassword01(@Param("login") Login login);
}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/LoginMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.LoginMapper">
    
    <select id="selectPersonByAccountAndPassword01" resultType="person">
        SELECT p.id, nickname
        FROM login l
                 INNER JOIN person p
        WHERE pid = p.id
          AND account = #{login.account}
          AND auth_text = #{login.authText}
    select>
mapper>

编写测试类

com.lihaozhe.mapper.LoginMapper.Test

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Login;
import com.lihaozhe.pojo.Person;
import com.lihaozhe.util.mybatis.MyBatisUtil;
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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.Reader;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午3:29
 */
public class LoginMapperTest {
    @Test
    public void selectPersonByAccountAndPassword01(){
        Login login = new Login("13925135946", "123456");
        SqlSession sqlSession = MyBatisUtil.openSqlSession();
        LoginMapper mapper = sqlSession.getMapper(LoginMapper.class);
        Person person = mapper.selectPersonByAccountAndPassword01(login);
        MyBatisUtil.close();
        System.out.println(person);
    }
}

resultMap 同一映射配置文件内

编写接口

com.lihaozhe.mapper.LoginMapper

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Login;
import com.lihaozhe.pojo.Person;
import org.apache.ibatis.annotations.Param;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午3:27
 */
public interface LoginMapper {

    /**
     * 用户登录
     *
     * @param login 登录参数 account password
     * @return
     */
    Person selectByAccountAndPassword02(@Param("login") Login login);
}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/LoginMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.LoginMapper">
    <resultMap id="PersonMap" type="person">
        <id property="id" column="id"/>
        <result property="uuid" column="uuid"/>
        <result property="mobile" column="mobile"/>
        <result property="nickname" column="nickname"/>
        <result property="idCard" column="id_card"/>
    resultMap>
    
    <select id="selectPersonByAccountAndPassword02" resultMap="PersonMap">
        SELECT p.id, nickname
        FROM login l
                 INNER JOIN person p
        WHERE pid = p.id
          AND account = #{login.account}
          AND auth_text = #{login.authText}
    select>
mapper>

编写测试类

com.lihaozhe.mapper.LoginMapper.Test

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Login;
import com.lihaozhe.pojo.Person;
import com.lihaozhe.util.mybatis.MyBatisUtil;
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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.Reader;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午3:29
 */
public class LoginMapperTest {
    @Test
    public void selectPersonByAccountAndPassword02(){
        Login login = new Login("13925135946", "123456");
        SqlSession sqlSession = MyBatisUtil.openSqlSession();
        LoginMapper mapper = sqlSession.getMapper(LoginMapper.class);
        Person person = mapper.selectPersonByAccountAndPassword02(login);
        MyBatisUtil.close();
        System.out.println(person);
    }
}

resultMap 跨射配置文件内

编写接口

com.lihaozhe.mapper.LoginMapper

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Login;
import com.lihaozhe.pojo.Person;
import org.apache.ibatis.annotations.Param;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午3:27
 */
public interface LoginMapper {

    /**
     * 用户登录
     *
     * @param login 登录参数 account password
     * @return
     */
    Person selectByAccountAndPassword03(@Param("login") Login login);
}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/LoginMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.LoginMapper">
    
    <select id="selectPersonByAccountAndPassword03" resultMap="com.lihaozhe.mapper.PersonMapper.PersonMap">
        SELECT p.id, nickname
        FROM login l
                 INNER JOIN person p
        WHERE pid = p.id
          AND account = #{login.account}
          AND auth_text = #{login.authText}
    select>
mapper>

编写测试类

com.lihaozhe.mapper.LoginMapper.Test

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Login;
import com.lihaozhe.pojo.Person;
import com.lihaozhe.util.mybatis.MyBatisUtil;
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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.Reader;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午3:29
 */
public class LoginMapperTest {
    @Test
    public void selectPersonByAccountAndPassword03(){
        Login login = new Login("13925135946", "123456");
        SqlSession sqlSession = MyBatisUtil.openSqlSession();
        LoginMapper mapper = sqlSession.getMapper(LoginMapper.class);
        Person person = mapper.selectPersonByAccountAndPassword03(login);
        MyBatisUtil.close();
        System.out.println(person);
    }
}

association

编写VO类

com.lihaozhe.vo.PersonVo

package com.lihaozhe.vo;

import com.lihaozhe.pojo.Login;
import com.lihaozhe.pojo.Person;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/10 下午2:19
 */
public class PersonVo implements Serializable {
    private static final long serialVersionUID = -2348274078216811958L;
    /**
     * 登录信息
     */
    private Login login;
    /**
     * 员工信息
     */
    private Person person;
}

编写接口

com.lihaozhe.mapper.PersonMapper

package com.lihaozhe.mapper;

import com.lihaozhe.vo.PersonVo;
import org.apache.ibatis.annotations.Param;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午3:27
 */
public interface PersonMapper {

    /**
     * 根据id获取用户详细信息包括登录信息
     *
     * @param id 用户ID
     * @return
     */
    PersonVo selectPersonVoById(@Param("id") long id);
}

在核心配置文件配置别名映射
<typeAliases>
    <package name="com.lihaozhe.pojo"/>
    <package name="com.lihaozhe.vo"/>
typeAliases>
编写映射配置文件

src/main/resources/com/lihaozhe/mapper/PersonMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.PersonMapper">
    <resultMap id="PersonVoMap" type="personVo">
        <association property="login">
            <id property="id" column="lid"/>
            <result property="account" column="account"/>
            <result property="authText" column="auth_text"/>
            <result property="pid" column="pid"/>
        association>
        <association property="person">
            <id property="id" column="pid"/>
            <result property="uuid" column="uuid"/>
            <result property="mobile" column="mobile"/>
            <result property="nickname" column="nickname"/>
            <result property="idCard" column="id_card"/>
        association>
    resultMap>
    
    <select id="selectPersonVoById" resultMap="PersonVoMap">
        SELECT l.id AS lid,
               account,
               auth_text,
               pid,
               uuid,
               mobile,
               nickname,
               id_card
        FROM login l
                 inner join person p
        WHERE pid = p.id
          and pid = #{id}
    select>
mapper>

编写测试类

com.lihaozhe.mapper.PersonMapperTest

package com.lihaozhe.mapper;

import com.lihaozhe.vo.PersonVo;
import com.lihaozhe.util.mybatis.MyBatisUtil;
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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.Reader;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午3:29
 */
public class PersonMapperTest {
    private SqlSession sqlSession;

    // JUnit5 @BeforeAll和@BeforeEach注解替换了 JUnit4 中的@Before注解。
    // 它⽤于表⽰应在当前类中的每个@Test⽅法之前执⾏注解⽅法。
    // 注意:@BeforeAll注解的⽅法必须为静态⽅法,否则它将引发运⾏时错误。
    // 注意:@BeforeEach注解的⽅法不得为静态⽅法,否则它将引发运⾏时错误。
    @BeforeEach
    public void openSqlSession() throws IOException {
        // 核心配置文件classpath路径
        String resource = "mybatis/mybatis-config.xml";
        // 加载配置文件
        Reader reader = Resources.getResourceAsReader(resource);
        // 构建会话工厂
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
        // 从SqlSessionFactory对象中获取SqlSession
        sqlSession = sessionFactory.openSession();
    }
    
    @Test
    public void selectPersonVoById(){
        PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
        PersonVo personVo = mapper.selectPersonVoById(3L);
        sqlSession.close();
        System.out.println(personVo);
    }
}

多对一

写法与一对一完全一致

下面的案例使用关联查询和子查询分别实现

编写VO类

com.lihaozhe.vo.SonVo

package com.lihaozhe.vo;

import com.lihaozhe.pojo.Father;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/14 上午9:46
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SonVo implements Serializable {
    private static final long serialVersionUID = -203988976020008362L;
    /**
     * 儿子ID
     */
    private long sId;
    /**
     * 儿子姓名
     */
    private String sName;
    /**
     * 该儿子父亲ID
     */
    private long fId;
    /**
     * 该儿子父亲信息
     */
    private Father father;
}

  1. 联合查询

编写接口

com.lihaozhe.mapper.SonMapper

package com.lihaozhe.mapper;

import com.lihaozhe.vo.SonVo;
import org.apache.ibatis.annotations.Param;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/10 下午3:01
 */
public interface SonMapper {
    /**
     * 根据儿子ID查询儿子和该儿子父亲的信息
     *
     * @param sid
     * @return
     */
    SonVo selectSonVoBySid(@Param("sid") long sid);
}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/SonMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.SonMapper">
    
    <resultMap id="SonVoMap" type="sonVo">
        <id property="sId" column="s_id"/>
        <result property="sName" column="s_name"/>
        <result property="fId" column="fid"/>
        <association property="father">
            <id property="fId" column="fid"/>
            <result property="fName" column="f_name"/>
        association>
    resultMap>
    <select id="selectSonVoBySid" resultMap="SonVoMap">
        SELECT s_id, s_name, s.f_id AS fid, f_name
        FROM son s
                 INNER JOIN father f ON s.f_id = f.f_id AND s_id = #{sid}
    select>
mapper>

编写测试类

com.lihaozhe.mapper.SonMapperTest

package com.lihaozhe.mapper;

import com.lihaozhe.util.mybatis.MyBatisUtil;
import com.lihaozhe.vo.SonVo;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/10 下午3:13
 */
public class SonMapperTest {
    @Test
    public void selectSonVoBySid() {
        SqlSession sqlSession = MyBatisUtil.openSqlSession();
        SonMapper mapper = sqlSession.getMapper(SonMapper.class);
        SonVo sonVo = mapper.selectSonVoBySid(3L);
        MyBatisUtil.close();
        System.out.println(sonVo);
    }
}

  1. 子查询

编写接口

com.lihaozhe.mapper.FatherMapper

package com.lihaozhe.mapper;

import com.lihaozhe.vo.FatherVo;
import org.apache.ibatis.annotations.Param;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/10 上午11:15
 */
public interface FatherMapper {
    /**
     * 根据父亲ID获取父亲信息
     *
     * @param fid
     * @return
     */
    Father selectFatherById(@Param("fid") long fid);
}

com.lihaozhe.mapper.SonMapper

package com.lihaozhe.mapper;

import com.lihaozhe.vo.SonVo;
import org.apache.ibatis.annotations.Param;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/10 上午11:08
 */
public interface SonMapper {
    /**
     * 根据儿子ID查询儿子和该儿子父亲的信息
     *
     * @param sid
     * @return
     */
    SonVo selectSonVoById(@Param("sid") long sid);
}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/FatherMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.FatherMapper">
    
    <select id="selectFatherById" resultType="father">
        SELECT *
        FROM `father`
        WHERE `f_id` = #{fid}
    select>
mapper>

src/main/resources/com/lihaozhe/mapper/SonMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.SonMapper">
    
    <resultMap id="SonVoMapper" type="sonVo">
        <id property="sId" column="s_id"/>
        <result property="sName" column="s_name"/>
        <result property="fId" column="f_id"/>
        <association property="father" column="f_id" select="com.lihaozhe.mapper.FatherMapper.selectFatherById"/>
    resultMap>
    <select id="selectSonVoById" resultMap="SonVoMapper">
        SELECT *
        FROM `son`
        WHERE `s_id` = #{sid}
    select>
mapper>

编写测试类

com.lihaozhe.mapper.FatherMapperTest

package com.lihaozhe.mapper;

import com.lihaozhe.util.mybatis.MyBatisUtil;
import com.lihaozhe.vo.FatherVo;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/10 上午11:22
 */
public class FatherMapperTest {
    @Test
    public void selectFatherById(){
        SqlSession sqlSession = MyBatisUtil.openSqlSession();
        FatherMapper mapper = sqlSession.getMapper(FatherMapper.class);
        Father father = mapper.selectFatherById(1L);
        MyBatisUtil.close();
        System.out.println(father);
    }
}

com.lihaozhe.mapper.SonMapperTest

package com.lihaozhe.mapper;

import com.lihaozhe.util.mybatis.MyBatisUtil;
import com.lihaozhe.vo.SonVo;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/10 上午11:33
 */
public class SonMapperTest {
    @Test
    public void selectSonVoById() {
        SqlSession sqlSession = MyBatisUtil.openSqlSession();
        SonMapper mapper = sqlSession.getMapper(SonMapper.class);
        SonVo sonVo = mapper.selectSonVoById(3L);
        MyBatisUtil.close();
        System.out.println(sonVo);
    }
}

解析SQL

==>  Preparing: SELECT s_id, s_name,f_id FROM son WHERE s_id = ?
==> Parameters: 1(Long)
<==    Columns: s_id, s_name, f_id
<==        Row: 1, 李金吒, 1
====>  Preparing: SELECT f_id, f_name FROM father WHERE f_id = ?
====> Parameters: 1(Integer)
<====    Columns: f_id, f_name
<====        Row: 1, 李靖
<====      Total: 1
<==      Total: 1

一对多

下面的案例使用子查询和联合查询分别实现

编写VO类

com.lihaozhe.vo.FatherVo

package com.lihaozhe.vo;

import com.lihaozhe.pojo.Son;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.List;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/14 上午10:27
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FatherVo implements Serializable {
    private static final long serialVersionUID = -1335512987974717220L;
    /**
     * 父亲ID
     */
    private long fId;
    /**
     * 父亲姓名
     */
    private String fName;
    /**
     * 该父亲的儿子们
     */
    private List<Son> sons;
}

  1. 子查询

编写接口

com.lihaozhe.mapper.SonMapper

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Son;
import com.lihaozhe.vo.SonVo;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/10 上午11:08
 */
public interface SonMapper {
    /**
     * 根据父亲ID获取该父亲的儿子列表
     * @param fid
     * @return
     */
    List<Son> selectAllByFId(@Param("fid") long fid);
}

com.lihaozhe.mapper.FatherMapper

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Father;
import com.lihaozhe.vo.FatherVo;
import org.apache.ibatis.annotations.Param;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/10 上午11:15
 */
public interface FatherMapper {
    /**
     * 根据父亲ID获取父亲及其儿子们的信息
     *
     * @param fid
     * @return
     */
    FatherVo selectFatherVoById(@Param("fid") long fid);
}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/SonMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.SonMapper">
    
    <select id="selectAllByFId" resultType="son">
        select *
        from son
        where f_id = #{fid};
    select>
mapper>

src/main/resources/com/lihaozhe/mapper/FatherMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.FatherMapper">
    
    <resultMap id="FatherVoMap" type="fatherVo">
        <id property="fId" column="f_id"/>
        <result property="fName" column="f_name"/>
        <collection property="sons" ofType="son" column="f_id" select="com.lihaozhe.mapper.SonMapper.selectAllByFId"/>
    resultMap>
    <select id="selectFatherVoById" resultMap="FatherVoMap">
        select *
        from father
        where f_id = #{fid};
    select>
mapper>

编写测试类

com.lihaozhe.mapper.SonMapperTest

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Son;
import com.lihaozhe.util.mybatis.MyBatisUtil;
import com.lihaozhe.vo.SonVo;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

import java.util.List;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/10 上午11:33
 */
public class SonMapperTest {
    @Test
    public void selectAllByFId(){
        SqlSession sqlSession = MyBatisUtil.openSqlSession();
        SonMapper mapper = sqlSession.getMapper(SonMapper.class);
        List<Son> sons = mapper.selectAllByFId(1L);
        MyBatisUtil.close();
        sons.forEach(System.out::println);
    }
}

com.lihaozhe.mapper.FatherMapperTest

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Father;
import com.lihaozhe.util.mybatis.MyBatisUtil;
import com.lihaozhe.vo.FatherVo;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/10 上午11:22
 */
public class FatherMapperTest {
    @Test
    public void selectFatherVoById(){
        SqlSession sqlSession = MyBatisUtil.openSqlSession();
        FatherMapper mapper = sqlSession.getMapper(FatherMapper.class);
        FatherVo fatherVo = mapper.selectFatherVoById(1L);
        MyBatisUtil.close();
        System.out.println(fatherVo);
    }
}

解析SQL

==>  Preparing: SELECT f_id, f_name FROM father WHERE f_id = ?
==> Parameters: 1(Long)
<==    Columns: f_id, f_name
<==        Row: 1, 李靖
====>  Preparing: SELECT s_id, s_name,f_id FROM son WHERE f_id = ?
====> Parameters: 1(Integer)
<====    Columns: s_id, s_name, f_id
<====        Row: 1, 李金吒, 1
<====        Row: 2, 李木吒, 1
<====        Row: 3, 李哪吒, 1
<====      Total: 3
<==      Total: 1
  1. 联合查询用例

编写接口

com.lihaozhe.mapper.FatherMapper

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Father;
import com.lihaozhe.vo.FatherVo;
import org.apache.ibatis.annotations.Param;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/10 下午3:49
 */
public interface FatherMapper {
    /**
     * 根据父亲ID获取父亲及其儿子们的信息
     *
     * @param fid
     * @return
     */
    FatherVo selectFatherVoBySid(@Param("fid") long fid);
}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/FatherMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.FatherMapper">
    
    <resultMap id="FatherVoMapper" type="fatherVo">
        <id property="fId" column="fid"/>
        <result property="fName" column="f_name"/>
        <collection property="sons" ofType="son">
            <id property="sId" column="s_id"/>
            <result property="sName" column="s_name"/>
            <result property="fId" column="fid"/>
        collection>
    resultMap>
    <select id="selectFatherVoBySid" resultMap="FatherVoMapper">
        select f.f_id as fid, f_name, s_id, s_name
        from father f
                 inner join son s on f.f_id = s.f_id and f.f_id = #{fid}
    select>
mapper>

编写测试类

com.lihaozhe.mapper.FatherMapperTest

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Father;
import com.lihaozhe.util.mybatis.MyBatisUtil;
import com.lihaozhe.vo.FatherVo;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/10 下午3:52
 */
public class FatherMapperTest {
    @Test
    public void selectFatherVoBySid(){
        SqlSession sqlSession = MyBatisUtil.openSqlSession();
        FatherMapper mapper = sqlSession.getMapper(FatherMapper.class);
        FatherVo fatherVo = mapper.selectFatherVoBySid(1L);
        MyBatisUtil.close();
        System.out.println(fatherVo);
    }

}

多对多

  • 直接多对多
  • 间接多对多 将多对多拆成两个一对多 或 两个多对一

直接多对多

需求:查找某图书类目下的所有图书信息

编写VO类

com.lihaozhe.vo.CategoryVo

package com.lihaozhe.vo;

import com.lihaozhe.pojo.Book;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.List;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/14 上午11:27
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CategoryVo implements Serializable {
    private static final long serialVersionUID = 5565769402064534797L;
    /**
     * 分类ID
     */
    private long cid;
    /**
     * 分类名称
     */
    private String cname;
    /**
     * 某分类的图书列表
     */
    private List<Book> books;
}

编写接口

com.lihaozhe.mapper.CategoryMapper

package com.lihaozhe.mapper;

import com.lihaozhe.vo.CategoryVo;
import org.apache.ibatis.annotations.Param;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/14 上午11:28
 */
public interface CategoryMapper {
    /**
     * 根据分类ID获取分类及其分类下的图书列表
     *
     * @param cid
     * @return
     */
    CategoryVo selectCategoryVoByCid(@Param("cid") long cid);
}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/CategoryMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.CategoryMapper">
    
    <resultMap id="CategoryVoMap" type="categoryVo">
        <id property="cid" column="cid"/>
        <id property="cname" column="cname"/>
        <collection property="books" ofType="book">
            <id property="bid" column="bid"/>
            <result property="bname" column="bname"/>
        collection>
    resultMap>
    <select id="selectCategoryVoByCid" resultMap="CategoryVoMap">
        select cid, cname, bid, bname
        from category
                 inner join book_category
                 inner join book
                            on cid = m_cid and bid = m_bid and cid = #{cid}
    select>
mapper>
编写测试类

com.lihaozhe.mapper.CategoryMapperTest

package com.lihaozhe.mapper;

import com.lihaozhe.util.mybatis.MyBatisUtil;
import com.lihaozhe.vo.CategoryVo;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/14 上午11:34
 */
public class CategoryMapperTest {

    @Test
    public void selectCategoryVoByCid(){
        SqlSession sqlSession = MyBatisUtil.openSqlSession();
        CategoryMapper mapper = sqlSession.getMapper(CategoryMapper.class);
        CategoryVo categoryVo = mapper.selectCategoryVoByCid(3L);
        MyBatisUtil.close();
        System.out.println(categoryVo);
    }
}

需求:查找某图书的分类信息

编写VO类

com.lihaozhe.vo.BookVo

package com.lihaozhe.vo;

import com.lihaozhe.pojo.Category;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.List;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/14 上午11:36
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BookVo implements Serializable {
    private static final long serialVersionUID = 6785352134653400094L;
    /**
     * 书的ID
     */
    private long bid;
    /**
     * 书名
     */
    private String bname;
    /**
     * 某图书的分类信息列表
     */
    private List<Category> categories;
}

编写接口

com.lihaozhe.mapper.BookMapper

package com.lihaozhe.mapper;

import com.lihaozhe.vo.BookVo;
import org.apache.ibatis.annotations.Param;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/14 上午11:38
 */
public interface BookMapper {
    /**
     * 根据图书ID查询图书信息包括该图书的分类信息
     *
     * @param bid
     * @return
     */
    BookVo selectBookVoByBid(@Param("bid") long bid);
}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/BookMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.BookMapper">
    
    <resultMap id="BookVoMap" type="bookVo">
        <id property="bid" column="bid"/>
        <result property="bname" column="bname"/>
        <collection property="categories" ofType="category">
            <id property="cid" column="cid"/>
            <id property="cname" column="cname"/>
        collection>
    resultMap>
    <select id="selectBookVoByBid" resultMap="BookVoMap">
        select bid, bname, cid, cname
        from book
                 inner join book_category
                 inner join category
                            on bid = m_bid and cid = m_cid and bid = #{bid}
    select>
mapper>
编写测试类
package com.lihaozhe.mapper;

import com.lihaozhe.util.mybatis.MyBatisUtil;
import com.lihaozhe.vo.BookVo;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/14 上午11:34
 */
public class BookMapperTest {

    @Test
    public void test(){
        SqlSession sqlSession = MyBatisUtil.openSqlSession();
        BookMapper mapper = sqlSession.getMapper(BookMapper.class);
        BookVo bookVo = mapper.selectBookVoByBid(3L);
        MyBatisUtil.close();
        System.out.println(bookVo);
    }
}

间接多对多

编写中间表映射类

com.lihaozhe.pojo.StudentCourse

package com.lihaozhe.pojo;


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class StudentCourse implements Serializable {
    private static final long serialVersionUID = 7294808647412902387L;
    /**
     * 学生ID
     */
    private long sId;
    /**
     * 课程ID
     */
    private long cId;
    /**
     * 学生信息
     */
    private Student student;
    /**
     * 课程信息
     */
    private Course course;

}

编写接口

com.lihaozhe.mapper.CourseMapper

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Course;
import org.apache.ibatis.annotations.Param;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/11 下午3:04
 */
public interface CourseMapper {
    /**
     * 根据课程ID查找课程
     *
     * @param cid
     * @return
     */
    Course selectCourseByCid(@Param("cid") long cid);

}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/CourseMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.CourseMapper">

    
    <select id="selectCourseByCid" resultType="course">
        SELECT *
        FROM `course`
        WHERE `c_id` = #{cid}
    select>
mapper>
编写测试类

com.lihaozhe.mapper.CourseMapperTest

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Course;
import com.lihaozhe.util.mybatis.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/11 下午3:06
 */
public class CourseMapperTest {
    @Test
    public void selectCourseByCid(){
        SqlSession sqlSession = MyBatisUtil.openSqlSession();
        CourseMapper mapper = sqlSession.getMapper(CourseMapper.class);
        Course course = mapper.selectCourseByCid(3L);
        MyBatisUtil.close();
        System.out.println(course);
    }
}

编写接口

com.lihaozhe.mapper.StudentMapper

package com.lihaozhe.mapper;

import com.lihaozhe.vo.StudentVo;
import org.apache.ibatis.annotations.Param;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/11 下午3:08
 */
public interface StudentMapper {
    /**
     * 根据学生ID 查询学生信息 包含所需课程的ID列表
     *
     * @param sid
     * @return
     */
    StudentVo selectStudentVoBySid(@Param("sid") long sid);
}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/StudentMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.StudentMapper">
    
    <resultMap id="StudentVoMap" type="studentVo">
        <id property="sId" column="sid"/>
        <result property="sName" column="s_name"/>
        <collection property="studentCourses" ofType="studentCourse">
            <result property="sId" column="sid"/>
            <result property="cId" column="c_id"/>
            <association property="course" column="c_id" select="com.lihaozhe.mapper.CourseMapper.selectCourseByCid"/>
        collection>
    resultMap>
    <select id="selectStudentVoBySid" resultMap="StudentVoMap">
        select stu.s_id as sid, s_name, c_id
        from student as stu
                 inner join student_course sc on stu.s_id = sc.s_id and stu.s_id = #{sid}

    select>
mapper>
编写测试类

com.lihaozhe.mapper.StudentMapperTest

package com.lihaozhe.mapper;

import com.lihaozhe.util.mybatis.MyBatisUtil;
import com.lihaozhe.vo.StudentVo;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/11 下午3:23
 */
public class StudentMapperTest {
    @Test
    public void selectStudentVoBySid() {
        SqlSession sqlSession = MyBatisUtil.openSqlSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        StudentVo studentVo = mapper.selectStudentVoBySid(3L);
        System.out.println(studentVo);
        System.out.println(studentVo.getSName());
        studentVo.getStudentCourses().forEach(studentCourse -> System.out.println(studentCourse.getCourse()));
    }
}

SQL解析
==>  Preparing: SELECT s.s_id, s_name, c_id FROM `student` s INNER JOIN `student_course` sc ON s.s_id = sc.s_id AND s.s_id = ?
==> Parameters: 1(Long)
<==    Columns: s_id, s_name, c_id
<==        Row: 1, stu01, 1
====>  Preparing: SELECT * FROM `course` WHERE `c_id` = ?
====> Parameters: 1(Integer)
<====    Columns: c_id, c_name
<====        Row: 1, java
<====      Total: 1
<==        Row: 1, stu01, 2
====>  Preparing: SELECT * FROM `course` WHERE `c_id` = ?
====> Parameters: 2(Integer)
<====    Columns: c_id, c_name
<====        Row: 2, scala
<====      Total: 1
<==      Total: 2
编写接口

com.lihaozhe.mapper.StudentMapper

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Student;
import com.lihaozhe.vo.StudentVo;
import org.apache.ibatis.annotations.Param;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/11 下午3:08
 */
public interface StudentMapper {
    /**
     * 根据学生ID 查询学生信息 包含所需课程的ID列表
     *
     * @param sid
     * @return
     */
    StudentVo selectStudentVoBySid(@Param("sid") long sid);

    /**
     * 根据学生ID 查询学生信息
     *
     * @param sid
     * @return
     */
    Student selectStudentBySid(@Param("sid") long sid);
}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/StudentMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.StudentMapper">
    
    <resultMap id="StudentVoMap" type="studentVo">
        <id property="sId" column="sid"/>
        <result property="sName" column="s_name"/>
        <collection property="studentCourses" ofType="studentCourse">
            <result property="sId" column="sid"/>
            <result property="cId" column="c_id"/>
            <association property="course" column="c_id" select="com.lihaozhe.mapper.CourseMapper.selectCourseByCid"/>
        collection>
    resultMap>
    <select id="selectStudentVoBySid" resultMap="StudentVoMap">
        select stu.s_id as sid, s_name, c_id
        from student as stu
                 inner join student_course sc on stu.s_id = sc.s_id and stu.s_id = #{sid}

    select>

    
    <select id="selectStudentBySid" resultType="student">
        SELECT * FROM `student` WHERE `s_id` = #{sid}
    select>
mapper>
编写测试类

com.lihaozhe.mapper.StudentMapperTest

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Student;
import com.lihaozhe.util.mybatis.MyBatisUtil;
import com.lihaozhe.vo.StudentVo;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/11 下午3:23
 */
public class StudentMapperTest {
     @Test
    public void selectStudentVoBySid() {
        SqlSession sqlSession = MyBatisUtil.openSqlSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        StudentVo studentVo = mapper.selectStudentVoBySid(3L);
        System.out.println(studentVo);
        System.out.println(studentVo.getSName());
        studentVo.getStudentCourses().forEach(studentCourse -> System.out.println(studentCourse.getCourse()));
    }

    @Test
    public void selectStudentBySid() {
        SqlSession sqlSession = MyBatisUtil.openSqlSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        Student student = mapper.selectStudentBySid(3L);
        System.out.println(student);
    }
}

编写VO类

com.lihaozhe.vo.CourseVo

package com.lihaozhe.vo;

import com.lihaozhe.pojo.StudentCourse;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.List;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/14 下午12:22
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CourseVo implements Serializable {
    private static final long serialVersionUID = -2649136027724661116L;
    /**
     * 课程ID
     */
    private long cId;
    /**
     * 课程名称
     */
    private String cName;
    /**
     * 课程关联信息
     */
    private List<StudentCourse> studentCourses;
}

编写接口

com.lihaozhe.mapper.CourseMapper

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Course;
import com.lihaozhe.vo.CourseVo;
import org.apache.ibatis.annotations.Param;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/11 下午3:04
 */
public interface CourseMapper {
    /**
     * 根据课程ID查找课程
     *
     * @param cid
     * @return
     */
    Course selectCourseByCid(@Param("cid") long cid);

    /**
     * 根据课程ID查找课程 包含所需课程的ID列表
     *
     * @param cid
     * @return
     */
    CourseVo selectCourseVoByCid(@Param("cid") long cid);
}

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/CourseMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.CourseMapper">
    
    <select id="selectCourseByCid" resultType="course">
        SELECT *
        FROM `course`
        WHERE `c_id` = #{cid}
    select>

    
    <resultMap id="CourseVoMap" type="courseVo">
        <id property="cId" column="cid"/>
        <result property="cName" column="c_name"/>
        <collection property="studentCourses" ofType="studentCourse">
            <result property="sId" column="sid"/>
            <result property="cId" column="c_id"/>
            <association property="student" column="s_id" select="com.lihaozhe.mapper.StudentMapper.selectStudentBySid"/>
        collection>
    resultMap>
    <select id="selectCourseVoByCid" resultMap="CourseVoMap">
        select c.c_id as cid, c_name, s_id
        from course as c
                 inner join student_course sc on c.c_id = sc.c_id and c.c_id = #{cid}
    select>
mapper>
编写测试类

com.lihaozhe.mapper.CourseMapperTest

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Course;
import com.lihaozhe.util.mybatis.MyBatisUtil;
import com.lihaozhe.vo.CourseVo;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/11 下午3:06
 */
public class CourseMapperTest {
    @Test
    public void selectCourseByCid(){
        SqlSession sqlSession = MyBatisUtil.openSqlSession();
        CourseMapper mapper = sqlSession.getMapper(CourseMapper.class);
        Course course = mapper.selectCourseByCid(3L);
        MyBatisUtil.close();
        System.out.println(course);
    }

    @Test
    public void selectCourseVoByCid(){
        SqlSession sqlSession = MyBatisUtil.openSqlSession();
        CourseMapper mapper = sqlSession.getMapper(CourseMapper.class);
        CourseVo courseVo = mapper.selectCourseVoByCid(3L);
        System.out.println(courseVo);
        System.out.println(courseVo.getCName());
        courseVo.getStudentCourses().forEach(studentCourse -> System.out.println(studentCourse.getStudent()));
    }
}

延迟加载

@Test
public void selectStudentVoBySid01() {
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    StudentVo studentVo = mapper.selectStudentVoBySid(1L);
    MyBatisUtil.close();
    System.out.println(studentVo.getSName());
}

Opening JDBC Connection
Created connection 379121284.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1698ee84]
==>  Preparing: SELECT s.s_id, s_name, c_id FROM `student` s INNER JOIN `student_course` sc ON s.s_id = sc.s_id AND s.s_id = ?
==> Parameters: 1(Long)
<==    Columns: s_id, s_name, c_id
<==        Row: 1, stu01, 1
====>  Preparing: SELECT * FROM `course` WHERE `c_id` = ?
====> Parameters: 1(Integer)
<====    Columns: c_id, c_name
<====        Row: 1, java
<====      Total: 1
<==        Row: 1, stu01, 2
====>  Preparing: SELECT * FROM `course` WHERE `c_id` = ?
====> Parameters: 2(Integer)
<====    Columns: c_id, c_name
<====        Row: 2, scala
<====      Total: 1
<==      Total: 2
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1698ee84]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1698ee84]
Returned connection 379121284 to pool.
@Test
public void selectStudentVoBySid02() {
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    StudentVo studentVo = mapper.selectStudentVoBySid(1L);
    MyBatisUtil.close();
    studentVo.getStudentCourses().forEach(studentCourse -> System.out.println(studentCourse.getCourse()));
}
Opening JDBC Connection
Created connection 379121284.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1698ee84]
==>  Preparing: SELECT s.s_id, s_name, c_id FROM `student` s INNER JOIN `student_course` sc ON s.s_id = sc.s_id AND s.s_id = ?
==> Parameters: 1(Long)
<==    Columns: s_id, s_name, c_id
<==        Row: 1, stu01, 1
====>  Preparing: SELECT * FROM `course` WHERE `c_id` = ?
====> Parameters: 1(Integer)
<====    Columns: c_id, c_name
<====        Row: 1, java
<====      Total: 1
<==        Row: 1, stu01, 2
====>  Preparing: SELECT * FROM `course` WHERE `c_id` = ?
====> Parameters: 2(Integer)
<====    Columns: c_id, c_name
<====        Row: 2, scala
<====      Total: 1
<==      Total: 2
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1698ee84]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1698ee84]
Returned connection 379121284 to pool.
Course(cId=1, cName=java)
Course(cId=2, cName=scala)

Process finished with exit code 0

从上面第一个案例可以看出客户只想查看学生休息并不想看学生所学专业信息 但是 仍然执行了子查询,

我们希望 当想看该学生和该学生所学专业详细信息的之后才走子查询而只看学生信息的时候不走子查询

于是我们开启了延迟加载

核心配置文件



<setting name="lazyLoadingEnabled" value="true"/>






@Test
public void selectStudentVoBySid01() {
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    StudentVo studentVo = mapper.selectStudentVoBySid(1L);
    MyBatisUtil.close();
    System.out.println(studentVo.getSName());
}

Opening JDBC Connection
Created connection 379121284.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1698ee84]
==>  Preparing: SELECT s.s_id, s_name, c_id FROM `student` s INNER JOIN `student_course` sc ON s.s_id = sc.s_id AND s.s_id = ?
==> Parameters: 1(Long)
<==    Columns: s_id, s_name, c_id
<==        Row: 1, stu01, 1
<==        Row: 1, stu01, 2
<==      Total: 2
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1698ee84]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1698ee84]
Returned connection 379121284 to pool.
@Test
public void selectStudentVoBySid02() {
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    StudentVo studentVo = mapper.selectStudentVoBySid(1L);
    MyBatisUtil.close();
    studentVo.getStudentCourses().forEach(studentCourse -> System.out.println(studentCourse.getCourse()));
}
Opening JDBC Connection
Created connection 544966217.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@207b8649]
==>  Preparing: SELECT s.s_id, s_name, c_id FROM `student` s INNER JOIN `student_course` sc ON s.s_id = sc.s_id AND s.s_id = ?
==> Parameters: 1(Long)
<==    Columns: s_id, s_name, c_id
<==        Row: 1, stu01, 1
<==        Row: 1, stu01, 2
<==      Total: 2
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@207b8649]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@207b8649]
Returned connection 544966217 to pool.
Opening JDBC Connection
Checked out connection 544966217 from pool.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@207b8649]
==>  Preparing: SELECT * FROM `course` WHERE `c_id` = ?
==> Parameters: 1(Integer)
<==    Columns: c_id, c_name
<==        Row: 1, java
<==      Total: 1
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@207b8649]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@207b8649]
Returned connection 544966217 to pool.
Course(cId=1, cName=java)
Opening JDBC Connection
Checked out connection 544966217 from pool.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@207b8649]
==>  Preparing: SELECT * FROM `course` WHERE `c_id` = ?
==> Parameters: 2(Integer)
<==    Columns: c_id, c_name
<==        Row: 2, scala
<==      Total: 1
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@207b8649]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@207b8649]
Returned connection 544966217 to pool.
Course(cId=2, cName=scala)

Process finished with exit code 0

侵入式延迟 积极加载

侵入式延迟 访问主对象及主对象里面的属性时,不光会加载主对象(即从数据库中查询主对象的信息),还会一同加载关联对象。 积极加载

深度延迟 访问主对象属性时,只加载主,只有当访问关联对象的属性时,才会去加载关联对象。 按需加载

<settings>
    
    <setting name="mapUnderscoreToCamelCase" value="true"/>
    
    <setting name="logImpl" value="STDOUT_LOGGING"/>
    
    
    <setting name="lazyLoadingEnabled" value="true"/>
    
    
    
    
    
settings>

映射配置文件中子查询设置fetchType

  • fetchType=“eager” 不支持懒加载

  • fetchType=“lzsy” 支持懒加载

@Test
public void selectDeptVoById01() {
    // 获取接口代理对象
    DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
    // 执行代理对象中方法
    mapper.selectDeptVoById(3L);
    // 释放资源
    sqlSession.close();
}
@Test
public void selectDeptVoById02() {
    // 获取接口代理对象
    DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
    // 执行代理对象中方法
    DeptVo deptVo = mapper.selectDeptVoById(3L);
    // 释放资源
    sqlSession.close();
    System.out.println(deptVo.getDname());
}
@Test
public void selectDeptVoById03() {
    // 获取接口代理对象
    DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
    // 执行代理对象中方法
    DeptVo deptVo = mapper.selectDeptVoById(3L);
    // 释放资源
    sqlSession.close();
    deptVo.getEmps();
}

一级缓存

编写测试类

com.lihaozhe.mapper.CacheTest

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Person;
import com.lihaozhe.util.mybatis.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/12 上午10:05
 */
public class CacheTest {
    @Test
    public void testCache01(){
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
        Person person01 = mapper.selectById(3L);
        Person person02 = mapper.selectById(3L);
        MyBatisUtil.close();
    }
}

Opening JDBC Connection
Created connection 1552870927.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5c8eee0f]
==>  Preparing: SELECT `id`, `uuid`, `mobile`, `nickname`, `id_card` FROM `person` WHERE `id` = ?
==> Parameters: 3(Long)
<==    Columns: id, uuid, mobile, nickname, id_card
<==        Row: 3, 5ee0074d47064285b8c5925534d70d84, 17674856547, 令狐荡, 649152199504171242
<==      Total: 1
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5c8eee0f]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5c8eee0f]
Returned connection 1552870927 to pool.
package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Person;
import com.lihaozhe.util.mybatis.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/12 上午10:05
 */
public class CacheTest {
    @Test
    public void testCache02() {
        SqlSession sqlSession = MyBatisUtil.openSqlSession();
        PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
        Person person01 = mapper.selectById(6L);
        Person person02 = mapper.selectById(3L);
        MyBatisUtil.close();
    }0
}

Opening JDBC Connection
Created connection 1552870927.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5c8eee0f]
==>  Preparing: SELECT `id`, `uuid`, `mobile`, `nickname`, `id_card` FROM `person` WHERE `id` = ?
==> Parameters: 6(Long)
<==    Columns: id, uuid, mobile, nickname, id_card
<==        Row: 6, aebe1bd701b24fb89347c78bb3aaf938, 13651227685, 欧阳脓, 644102199803081660
<==      Total: 1
==>  Preparing: SELECT `id`, `uuid`, `mobile`, `nickname`, `id_card` FROM `person` WHERE `id` = ?
==> Parameters: 3(Long)
<==    Columns: id, uuid, mobile, nickname, id_card
<==        Row: 3, 5ee0074d47064285b8c5925534d70d84, 17674856547, 令狐荡, 649152199504171242
<==      Total: 1
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5c8eee0f]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5c8eee0f]
Returned connection 1552870927 to pool.
package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Person;
import com.lihaozhe.util.mybatis.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/12 上午10:05
 */
public class CacheTest {

    @Test
    public void testCache03() {
        SqlSession sqlSession = MyBatisUtil.openSqlSession();
        PersonMapper mapper01 = sqlSession.getMapper(PersonMapper.class);
        PersonMapper mapper02 = sqlSession.getMapper(PersonMapper.class);
        Person person01 = mapper01.selectById(3L);
        Person person02 = mapper02.selectById(3L);
        MyBatisUtil.close();
    }
}

Opening JDBC Connection
Created connection 1552870927.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5c8eee0f]
==>  Preparing: SELECT `id`, `uuid`, `mobile`, `nickname`, `id_card` FROM `person` WHERE `id` = ?
==> Parameters: 3(Long)
<==    Columns: id, uuid, mobile, nickname, id_card
<==        Row: 3, 5ee0074d47064285b8c5925534d70d84, 17674856547, 令狐荡, 649152199504171242
<==      Total: 1
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5c8eee0f]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5c8eee0f]
Returned connection 1552870927 to pool.
package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Person;
import com.lihaozhe.util.mybatis.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/12 上午10:05
 */
public class CacheTest {

    @Test
    public void testCache04() {
        SqlSession sqlSession01 = MyBatisUtil.getSqlSession();
        PersonMapper mapper01 = sqlSession01.getMapper(PersonMapper.class);
        Person person01 = mapper01.selectById(3L);

        SqlSession sqlSession02 = MyBatisUtil.getSqlSession();
        PersonMapper mapper02 = sqlSession02.getMapper(PersonMapper.class);
        Person person02 = mapper02.selectById(3L);
        MyBatisUtil.close();
    }
}

Opening JDBC Connection
Created connection 1552870927.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5c8eee0f]
==>  Preparing: SELECT `id`, `uuid`, `mobile`, `nickname`, `id_card` FROM `person` WHERE `id` = ?
==> Parameters: 3(Long)
<==    Columns: id, uuid, mobile, nickname, id_card
<==        Row: 3, 5ee0074d47064285b8c5925534d70d84, 17674856547, 令狐荡, 649152199504171242
<==      Total: 1
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5c8eee0f]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5c8eee0f]
Returned connection 1552870927 to pool.
package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Person;
import com.lihaozhe.util.mybatis.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/12 上午10:05
 */
public class CacheTest {

    @Test
    public void testCache05() {
        SqlSession sqlSession01 = MyBatisUtil.getSqlSession();
        PersonMapper mapper01 = sqlSession01.getMapper(PersonMapper.class);
        Person person01 = mapper01.selectById(3L);
        MyBatisUtil.close();
        
        SqlSession sqlSession02 = MyBatisUtil.getSqlSession();
        PersonMapper mapper02 = sqlSession02.getMapper(PersonMapper.class);
        Person person02 = mapper02.selectById(3L);
        MyBatisUtil.close();
    }
}

Opening JDBC Connection
Created connection 1552870927.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5c8eee0f]
==>  Preparing: SELECT `id`, `uuid`, `mobile`, `nickname`, `id_card` FROM `person` WHERE `id` = ?
==> Parameters: 3(Long)
<==    Columns: id, uuid, mobile, nickname, id_card
<==        Row: 3, 5ee0074d47064285b8c5925534d70d84, 17674856547, 令狐荡, 649152199504171242
<==      Total: 1
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5c8eee0f]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5c8eee0f]
Returned connection 1552870927 to pool.
Opening JDBC Connection
Checked out connection 1552870927 from pool.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5c8eee0f]
==>  Preparing: SELECT `id`, `uuid`, `mobile`, `nickname`, `id_card` FROM `person` WHERE `id` = ?
==> Parameters: 3(Long)
<==    Columns: id, uuid, mobile, nickname, id_card
<==        Row: 3, 5ee0074d47064285b8c5925534d70d84, 17674856547, 令狐荡, 649152199504171242
<==      Total: 1
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5c8eee0f]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5c8eee0f]
Returned connection 1552870927 to pool.

结论:mybatis一级缓存默认开启,同一个SqlSession中查询条件一致则走一级缓存,一级缓存不能跨SqlSession

二级缓存

MyBatis如果想跨SqlSession缓存则可以采用将查询结果缓存至第三方,例如:

  • ehcache
  • memcached
  • redis

开启二级缓存步骤

maven项目提前在pom.xml文件中增加相关依赖

  1. 在核心配置文件中加入
<settings>
		<setting name="cacheEnabled" value="true" />
settings>
  1. 在映射配置文件中加入
    回收策略:
    LRU – 最近最少使用的:移除最长时间不被使用的对象。
    FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
    SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
    WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true" />
  1. 缓存遇到commit失效

  2. ehcache二级缓存在映射配置文件中加入

<cache type="org.mybatis.caches.ehcache.LoggingEhcache" />
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

添加maven依赖

<dependency>
    <groupId>org.ehcachegroupId>
    <artifactId>ehcacheartifactId>
    <version>3.9.9version>
dependency>
<dependency>
    <groupId>org.mybatis.cachesgroupId>
    <artifactId>mybatis-ehcacheartifactId>
    <version>1.2.2version>
dependency>

编写核心配置文件

<settings>
	
	<setting name="cacheEnabled" value="true" />
settings>

编写映射配置文件

src/main/resources/com/lihaozhe/mapper/PersonMapper.xml

添加以下内容


<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true" />

在需要缓存的查找标签增加设置useCache=true

<select id="selectById" resultType="person" useCache="true">
    <include refid="select_person">include>
    <where>
        `id` = #{id}
    where>
select>

编写测试类

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Person;
import com.lihaozhe.util.mybatis.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/12 上午10:05
 */
public class CacheTest {

    @Test
    public void testCache05() {
        SqlSession sqlSession01 = MyBatisUtil.openSqlSession();
        PersonMapper mapper01 = sqlSession01.getMapper(PersonMapper.class);
        Person person01 = mapper01.selectById(3L);
        MyBatisUtil.close();

        SqlSession sqlSession02 = MyBatisUtil.openSqlSession();
        PersonMapper mapper02 = sqlSession02.getMapper(PersonMapper.class);
        Person person02 = mapper02.selectById(3L);
        MyBatisUtil.close();
    }
}

Cache Hit Ratio [com.lihaozhe.mapper.PersonMapper]: 0.0
Opening JDBC Connection
Created connection 1045731788.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@3e5499cc]
==>  Preparing: SELECT `id`, `uuid`, `mobile`, `nickname`, `id_card` FROM `person` WHERE `id` = ?
==> Parameters: 3(Long)
<==    Columns: id, uuid, mobile, nickname, id_card
<==        Row: 3, 5ee0074d47064285b8c5925534d70d84, 17674856547, 令狐荡, 649152199504171242
<==      Total: 1
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@3e5499cc]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@3e5499cc]
Returned connection 1045731788 to pool.
Cache Hit Ratio [com.lihaozhe.mapper.PersonMapper]: 0.5
package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Person;
import com.lihaozhe.util.mybatis.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/12 上午10:05
 */
public class CacheTest {

    @Test
    public void testCache05() {
        SqlSession sqlSession01 = MyBatisUtil.openSqlSession();
        PersonMapper mapper01 = sqlSession01.getMapper(PersonMapper.class);
        Person person01 = mapper01.selectById(3L);
        MyBatisUtil.close();

        SqlSession sqlSession02 = MyBatisUtil.openSqlSession();
        PersonMapper mapper02 = sqlSession02.getMapper(PersonMapper.class);
        Person person02 = mapper02.selectById(3L);
        MyBatisUtil.close();
    }
}

Cache Hit Ratio [com.lihaozhe.mapper.PersonMapper]: 0.0
Opening JDBC Connection
Created connection 1045731788.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@3e5499cc]
==>  Preparing: SELECT `id`, `uuid`, `mobile`, `nickname`, `id_card` FROM `person` WHERE `id` = ?
==> Parameters: 6(Long)
<==    Columns: id, uuid, mobile, nickname, id_card
<==        Row: 6, aebe1bd701b24fb89347c78bb3aaf938, 13651227685, 欧阳脓, 644102199803081660
<==      Total: 1
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@3e5499cc]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@3e5499cc]
Returned connection 1045731788 to pool.
Cache Hit Ratio [com.lihaozhe.mapper.PersonMapper]: 0.0
Opening JDBC Connection
Checked out connection 1045731788 from pool.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@3e5499cc]
==>  Preparing: SELECT `id`, `uuid`, `mobile`, `nickname`, `id_card` FROM `person` WHERE `id` = ?
==> Parameters: 3(Long)
<==    Columns: id, uuid, mobile, nickname, id_card
<==        Row: 3, 5ee0074d47064285b8c5925534d70d84, 17674856547, 令狐荡, 649152199504171242
<==      Total: 1
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@3e5499cc]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@3e5499cc]
Returned connection 1045731788 to pool.

分页插件 pagehelper

引入maven依赖

<dependency>
    <groupId>com.github.pagehelpergroupId>
    <artifactId>pagehelperartifactId>
    <version>5.3.1version>
dependency>

完整pom.xml文件


<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0modelVersion>

  <groupId>com.lihaozhegroupId>
  <artifactId>mybatisartifactId>
  <version>1.0-SNAPSHOTversion>
  <name>mybatisname>
  <packaging>jarpackaging>

  <properties>
    <jdk.version>17jdk.version>
    <maven.compiler.source>17maven.compiler.source>
    <maven.compiler.target>17maven.compiler.target>
    <maven.compiler.compilerVersion>17maven.compiler.compilerVersion>
    <maven.compiler.encoding>utf-8maven.compiler.encoding>
    <project.build.sourceEncoding>utf-8project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
    <maven.test.failure.ignore>truemaven.test.failure.ignore>
    <maven.test.skip>truemaven.test.skip>
    <junit.version>5.8.2junit.version>

    <fastjson.version>2.0.6fastjson.version>
    <gson.version>2.9.0gson.version>
    <hutool.version>5.8.0.M3hutool.version>
    <jackson.version>2.13.3jackson.version>
    <lombok.version>1.18.24lombok.version>
    <java-testdata.version>1.1.2java-testdata.version>
  properties>

  <dependencies>
    <dependency>
      <groupId>org.junit.jupitergroupId>
      <artifactId>junit-jupiter-apiartifactId>
      <version>${junit.version}version>
      <scope>testscope>
    dependency>
    <dependency>
      <groupId>com.github.binarywanggroupId>
      <artifactId>java-testdata-generatorartifactId>
      <version>${java-testdata.version}version>
    dependency>
    
    
    <dependency>
      <groupId>org.apache.commonsgroupId>
      <artifactId>commons-lang3artifactId>
      <version>3.8.1version>
    dependency>
    
    <dependency>
      <groupId>commons-iogroupId>
      <artifactId>commons-ioartifactId>
      <version>2.11.0version>
    dependency>
    <dependency>
      <groupId>org.junit.jupitergroupId>
      <artifactId>junit-jupiter-engineartifactId>
      <version>${junit.version}version>
      <scope>testscope>
    dependency>
    <dependency>
      <groupId>cn.hutoolgroupId>
      <artifactId>hutool-allartifactId>
      <version>${hutool.version}version>
    dependency>
    <dependency>
      <groupId>org.projectlombokgroupId>
      <artifactId>lombokartifactId>
      <version>${lombok.version}version>
      <scope>providedscope>
    dependency>
    
    
    <dependency>
      <groupId>com.alibabagroupId>
      <artifactId>fastjsonartifactId>
      <version>${fastjson.version}version>
    dependency>
    
    <dependency>
      <groupId>com.google.code.gsongroupId>
      <artifactId>gsonartifactId>
      <version>${gson.version}version>
    dependency>
    
    <dependency>
      <groupId>com.fasterxml.jackson.coregroupId>
      <artifactId>jackson-coreartifactId>
      <version>${jackson.version}version>
    dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.coregroupId>
      <artifactId>jackson-annotationsartifactId>
      <version>${jackson.version}version>
    dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.coregroupId>
      <artifactId>jackson-databindartifactId>
      <version>${jackson.version}version>
    dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.datatypegroupId>
      <artifactId>jackson-datatype-jsr310artifactId>
      <version>${jackson.version}version>
    dependency>
    <dependency>
      <groupId>mysqlgroupId>
      <artifactId>mysql-connector-javaartifactId>
      <version>8.0.29version>
    dependency>
    <dependency>
      <groupId>org.mybatisgroupId>
      <artifactId>mybatisartifactId>
      <version>3.5.10version>
    dependency>
    <dependency>
      <groupId>com.alibabagroupId>
      <artifactId>druidartifactId>
      <version>1.2.8version>
    dependency>
    <dependency>
      <groupId>org.ehcachegroupId>
      <artifactId>ehcacheartifactId>
      <version>3.9.9version>
    dependency>
    <dependency>
      <groupId>org.mybatis.cachesgroupId>
      <artifactId>mybatis-ehcacheartifactId>
      <version>1.2.2version>
    dependency>
    <dependency>
      <groupId>com.github.pagehelpergroupId>
      <artifactId>pagehelperartifactId>
      <version>5.3.1version>
    dependency>
    <dependency>
      <groupId>org.springframeworkgroupId>
      <artifactId>spring-contextartifactId>
      <version>5.3.20version>
    dependency>
  dependencies>

  <build>
    
    
    <plugins>
      <plugin>
        <groupId>org.apache.maven.pluginsgroupId>
        <artifactId>maven-war-pluginartifactId>
        <version>3.3.2version>
      plugin>
      
      <plugin>
        <groupId>org.apache.maven.pluginsgroupId>
        <artifactId>maven-compiler-pluginartifactId>
        <version>3.8.1version>
        <configuration>
          
          <encoding>UTF-8encoding>
          
          <source>${jdk.version}source>
          <target>${jdk.version}target>
        configuration>
      plugin>
      <plugin>
        <groupId>org.apache.maven.pluginsgroupId>
        <artifactId>maven-clean-pluginartifactId>
        <version>3.2.0version>
      plugin>
      <plugin>
        <groupId>org.apache.maven.pluginsgroupId>
        <artifactId>maven-resources-pluginartifactId>
        <version>3.2.0version>
      plugin>
      
      <plugin>
        <groupId>org.apache.maven.pluginsgroupId>
        <artifactId>maven-surefire-pluginartifactId>
        <version>2.22.2version>
        <configuration>
          <skip>trueskip>
        configuration>
      plugin>
    plugins>
  build>
project>

编写核心配置文件

追加以下内容

<plugins>
    
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
        
        <property name="helperDialect" value="mysql"/>
        
        <property name="pageSizeZero" value="true"/>
        
        <property name="reasonable" value="true" />
    plugin>
plugins>

page参数详解

1. helperDialect :分页插件会自动检测当前的数据库链接,自动选择合适的分页方式。 你可以配置 helperDialect 属性来指定分页插件使用哪种方言。配置时,可以使用下面的缩写值:oracle , mysql , mariadb , sqlite , hsqldb , postgresql , db2 , sqlserver , informix , h2 , sqlserver2012 , derby
特别注意:使用 SqlServer2012 数据库时,需要手动指定为 sqlserver2012 ,否则会使用 SqlServer2005 的方式进行分页。 你也可以实现 AbstractHelperDialect ,然后配置该属性为实现类的全限定名称即可使用自定义的实现方法。

2. offsetAsPageNum :默认值为 false ,该参数对使用 RowBounds 作为分页参数时有效。 当该参数设置为 true 时,会将 RowBounds 中的 offset 参数当成 pageNum 使用,可以用页码和页面大小两个参数进行分页。

3. rowBoundsWithCount :默认值为 false ,该参数对使用 RowBounds 作为分页参数时有效。当该参数设置为 true 时,使用 RowBounds 分页会进行 count 查询。   

4. pageSizeZero :默认值为 false ,当该参数设置为 true 时,如果 pageSize=0 或者 RowBounds.limit = 0 就会查询出全部的结果(相当于没有执行分页查询,但是返回结果仍然是 Page 类型)。

5. reasonable :分页合理化参数,默认值为 false 。当该参数设置为 true 时, pageNum<=0 时会查询第一页, pageNum>pages (超过总数时),会查询最后一页。默认 false 时,直接根据参数进行查询。

6. params :为了支持 startPage(Object params) 方法,增加了该参数来配置参数映射,用于从对象中根据属性名取值, 可以配置 pageNum,pageSize,count,pageSizeZero,reasonable ,不配置映射的用默认值, 默认值为 pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero= pageSizeZero 。

7. supportMethodsArguments :支持通过 Mapper 接口参数来传递分页参数,默认值 false ,分页插件会从查询方法的参数值中,自动根据上面 params 配置的字段中取值,查找到合适的值时就会自动分页。 使用方法可以参考测试代码中的 com.github.pagehelper.test.basic 包下的 ArgumentsMapTest 和 ArgumentsObjTest 。

8. autoRuntimeDialect :默认值为 false 。设置为 true 时,允许在运行时根据多数据源自动识别对应方言的分页 (不支持自动选择 sqlserver2012 ,只能使用 sqlserver ),用法和注意事项参考下面的场景五。

9. closeConn :默认值为 true 。当使用运行时动态数据源或没有设置 helperDialect 属性自动获取数据库类型时,会自动获取一个数据库连接, 通过该属性来设置是否关闭获取的这个连接,默认 true 关闭,设置为 false 后,不会关闭获取的连接,这个参数的设置要根据自己选择的数据源来决定。

完整核心配置文件


DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    
    <properties resource="config.properties"/>
    <settings>
        
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        
        
        <setting name="lazyLoadingEnabled" value="true"/>
        
        
        <setting name="aggressiveLazyLoading" value="false"/>
        
        <setting name="cacheEnabled" value="true"/>
    settings>
    <typeAliases>
        
        
        
        
        <package name="com.lihaozhe.pojo"/>
        <package name="com.lihaozhe.vo"/>
    typeAliases>
    <plugins>
        
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            
            <property name="helperDialect" value="mysql"/>
            
            <property name="pageSizeZero" value="true"/>
            
            <property name="reasonable" value="true"/>
        plugin>
    plugins>
    
    
    <environments default="development">
        
        <environment id="development">
            
            
            <transactionManager type="JDBC"/>
            
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            dataSource>
        environment>

    environments>
    <mappers>
        
        
        
        
        
        
        
        <package name="com.lihaozhe.mapper"/>
    mappers>

configuration>

编写接口

com.lihaozhe.mapper.PersonMapper

package com.lihaozhe.mapper;

import com.lihaozhe.pojo.Person;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午1:47
 */
public interface PersonMapper {

    /**
     * 分页查询
     * @param person
     * @return
     */
    List<Person> select4page(@Param("person") Person person);
}

编写映射的配置文件

src/main/resources/com/lihaozhe/mapper/PersonMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lihaozhe.mapper.PersonMapper">

    <select id="select4page" resultType="person">
        SELECT *
        FROM `person`
        <trim prefix="where" prefixOverrides="AND|OR">
            <if test="person.mobile != null and person.mobile.length > 0 and person.mobile.length < 12">
                <bind name="like_mobile" value="'%'+ person.mobile +'%'"/>
                AND `mobile` LIKE #{like_mobile}
            if>
            <if test="person.mobile != null and person.mobile.length > 0 and person.mobile.length < 12">
                <bind name="like_nickname" value="'%'+ person.nickname +'%'"/>
                AND `nickname` LIKE #{like_nickname}
            if>
        trim>
    select>
mapper>

编写测试类

com.lihaozhe.mapper.PersonMapperTest

package com.lihaozhe.mapper;

import cn.binarywang.tools.generator.ChineseIDCardNumberGenerator;
import cn.binarywang.tools.generator.ChineseMobileNumberGenerator;
import cn.binarywang.tools.generator.ChineseNameGenerator;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.lihaozhe.pojo.Person;
import com.lihaozhe.util.mybatis.MyBatisUtil;
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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

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

/**
 * @author 李昊哲
 * @version 1.0.0 2022/7/7 下午1:51
 */
public class PersonMapperTest {
    private SqlSession sqlSession;

    // JUnit5 @BeforeAll和@BeforeEach注解替换了 JUnit4 中的@Before注解。
    // 它⽤于表⽰应在当前类中的每个@Test⽅法之前执⾏注解⽅法。
    // 注意:@BeforeAll注解的⽅法必须为静态⽅法,否则它将引发运⾏时错误。
    // 注意:@BeforeEach注解的⽅法不得为静态⽅法,否则它将引发运⾏时错误。
    @BeforeEach
    public void getSqlSession() throws IOException {
        // 核心配置文件classpath路径
        String resource = "mybatis/mybatis-config.xml";
        // 加载配置文件
        Reader reader = Resources.getResourceAsReader(resource);
        // 构建会话工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        // 从SqlSessionFactory对象中获取SqlSession
        sqlSession = sqlSessionFactory.openSession();
    }

    @Test
    public void select4page(){
        PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
        // 在执行代理对象中查询方法之前 开启分页
        PageHelper.startPage(10,5);
        // 准备查询条件
        Person person = new Person();
        // 开启分页后 执行代理对象中的查询方法
        List<Person> personList = mapper.select4page(person);
        sqlSession.close();
        PageInfo<Person> pageInfo = new PageInfo<>(personList);
        System.out.println(pageInfo);
        System.out.println(JSONObject.toJSONString(pageInfo));
        System.out.println(JSONObject.toJSONString(pageInfo.getList()));
    }
}

PageInfo类属性介绍

属性名 属性说明
pageNum 当前页
pageSize 每页的数量
size 当前页的数量
startRow 由于startRow和endRow不常用,这里说个具体的用法 可以在页面中"显示startRow到endRow 共size条数据" 当前页面第一个元素在数据库中的行号
endRow
pages 总页数
prePage 前一页
nextPage 下一页
isFirstPage 是否为第一页
isLastPage 是否为最后一页
hasPreviousPage 是否有前一页
hasNextPage 是否有下一页
navigatePages 导航页码数
navigatepageNums 所有导航页号
nnavigateFirstPage 导航条上的第一页
navigateLastPage 导航条上的最后一页
list 数据集合
total 总数量

完整核心配置文件


DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    
    <properties resource="config.properties"/>
    <settings>
        
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        
        
        <setting name="lazyLoadingEnabled" value="true"/>
        
        
        <setting name="aggressiveLazyLoading" value="false"/>
        
        
    settings>
    <typeAliases>
        
        
        
        
        <package name="com.lihaozhe.pojo"/>
        <package name="com.lihaozhe.vo"/>
    typeAliases>
    <plugins>
        
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            
            
            <property name="helperDialect" value="mysql"/>
            
            <property name="pageSizeZero" value="true"/>
            
            <property name="reasonable" value="true" />
        plugin>
    plugins>
    
    
    <environments default="development">
        
        <environment id="development">
            
            
            <transactionManager type="JDBC"/>
            
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            dataSource>
        environment>
    environments>
    
    <mappers>
        
        
        
        
        
        <package name="com.lihaozhe.mapper"/>
    mappers>
configuration>

你可能感兴趣的:(Mybatis,大数据,Java,mybatis,mysql,数据库,java,大数据)