Mybatis 多对一和一对多查询

文章目录

Mybatis 多对一 and 一对多查询详解

数据库

员工表 t_emp

部门表 t_dept

sql 复制代码
CREATE TABLE `t_emp` (
  `emp_id` int NOT NULL AUTO_INCREMENT,
  `emp_name` varchar(25) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  `age` int DEFAULT NULL,
  `gender` varchar(25) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  `dept_id` int DEFAULT NULL,
  PRIMARY KEY (`emp_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;


CREATE TABLE `t_dept` (
  `dept_id` int NOT NULL AUTO_INCREMENT,
  `dept_name` varchar(25) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  PRIMARY KEY (`dept_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;


INSERT INTO `t_emp` (`emp_id`, `emp_name`, `age`, `gender`, `dept_id`) VALUES (1, '张三', 20, '男', 1), (2, '李四', 22, '男', 2), (3, '王五', 23, '男', 3), (4, '赵六', 24, '男', 1);


INSERT INTO `t_dept` (`dept_id`, `dept_name`) VALUES (1, 'A'), (2, 'B'), (3, 'C');

需求

多对一:员工表对应部门表

查询指定id的员工以及其对应的部门

一对多:部门表对应员工表

查询指定的部门以及其包含的员工

Mybatis代码

DeptMapper接口文件

java 复制代码
package com.atguigu.mybatis.mapper;

import com.ruanjian.pojo.Dept;
import com.ruanjian.pojo.Emp;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface DeptMapper {
    // 一对多查询
    // 查询部门表中的员工信息
    // 需要在部门类中添加员工的集合  private List<Emp> emps;

    Dept getDeptAndEmpById(@Param("deptId") Integer deptId);

  
    // 分步查询
    // 1.先查出指定id的部门信息,部门信息中有对应员工的dept_id

    Dept getDeptAndEmpByStepOne(@Param("deptId") int deptId);

    // 2.再根据dept_id查出相对应的员工信息
    List<Emp> getDeptAndEmpByStepTwo(@Param("deptId") int deptId);

}

EmpMapper接口文件

java 复制代码
package com.atguigu.mybatis.mapper;
import com.ruanjian.pojo.Dept;
import com.ruanjian.pojo.Emp;
import org.apache.ibatis.annotations.Param;

public interface EmpMapper {
    
    // 多对一查询
    // 查询指定id员工以及该员工所对应的部门信息

    Emp getEmpAndDeptById(@Param("empId") Integer empId);

    Emp getEmpAndDeptById_association(@Param("empId") Integer empId);

    // 分步查询
    // 先从员工表中查询出指定id的员工的数据,该数据中有对应部门id
    // 再根据部门id从部门表中查询出对应的部门信息

    // 分步查询第一步
    Emp getEmpAndDeptByIdOne(@Param("empId") Integer empId);

    // 分步查询第二步
    Dept getEmpAndDeptByIdTwo(@Param("deptId") Integer deptId);
}

Dept类文件 部门实体类

java 复制代码
package com.ruanjian.pojo;

/*
员工对部门 是多对一,多对一是在多的那个类(员工类)中添加一个部门对象
部门对员工 是一对多,一对多是在一的那个类中(部门类)中添加一个员工集合

对一 对的就是一个对象
对多 对的就是一个集合
 */

import java.util.List;

// 部门实体类
public class Dept {
    private Integer deptId;
    private String deptName;

    private List<Emp> emps;  // 添加的一个员工的集合

    public Dept() {
    }

    public Dept(Integer deptId, String deptName) {
        this.deptId = deptId;
        this.deptName = deptName;
    }

    public Integer getDeptId() {
        return deptId;
    }

    public void setDeptId(Integer deptId) {
        this.deptId = deptId;
    }

    public String getDeptName() {
        return deptName;
    }

    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }

    public List<Emp> getEmps() {
        return emps;
    }

    public void setEmps(List<Emp> emps) {
        this.emps = emps;
    }

    @Override
    public String toString() {
        return "Dept{" +
                "deptId=" + deptId +
                ", deptName='" + deptName + '\'' +
                ", emps=" + emps +
                '}';
    }
}

Emp类文件

员工实体类

java 复制代码
package com.ruanjian.pojo;

/*
员工对部门 是多对一,多对一是在多的那个类(员工类)中添加一个部门对象
部门对员工 是一对多,一对多是在一的那个类中(部门类)中添加一个员工集合

对一 对的就是一个对象
对多 对的就是一个集合
 */


// 员工实体类

// 对一就是对应的一个对象
// 对多就是对应的一个集合
public class Emp {
    private Integer empId;
    private String empName;
    private Integer age;
    private String gender;

    private Dept dept;  // 加上一个部门的对象


    public Emp() {
    }

    public Emp(Integer empId, String empName, Integer age, String gender) {
        this.empId = empId;
        this.empName = empName;
        this.age = age;
        this.gender = gender;
    }

    public Integer getEmpId() {
        return empId;
    }

    public void setEmpId(Integer empId) {
        this.empId = empId;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public Dept getDept() {
        return dept;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "empId=" + empId +
                ", empName='" + empName + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                ", dept=" + dept +
                '}';
    }
}

DeptMapper

xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.mybatis.mapper.DeptMapper">

<!-- 处理一对多的映射关系
    1. collection
    2. 分步查询
-->
<!--*************************** 一对多 collection ****************************************-->

    <resultMap id="deptAndEmpById_resultMap" type="dept">
        <id column="dept_id" property="deptId"></id>
        <result column="dept_name" property="deptName"></result>
        <!--    collection : 处理一对多的映射关系(处理集合类型的属性)-->
        <!--        ofType表示的是集合中的类型-->
        <collection property="emps" ofType="Emp">
            <id column="emp_id" property="empId"></id>
            <result column="emp_name" property="empName"></result>
            <result column="age" property="age"></result>
            <result column="gender" property="gender"></result>
        </collection>

    </resultMap>

    <!--    Dept getDeptAndEmpById(@Param("deptId") Integer deptId);-->
    <select id="getDeptAndEmpById" resultMap="deptAndEmpById_resultMap">
        select *
        from t_dept
        left join t_emp on t_dept.dept_id = t_emp.dept_id
        where t_dept.dept_id=#{deptId}
    </select>


<!--*************************** 一对多 collection ****************************************-->

<!--*************************** 一对多  分步查询  ****************************************-->

    <resultMap id="deptAndEmpResultMapByStep" type="Dept">
        <id column="dept_id" property="deptId"></id>
        <result column="dept_name" property="deptName"></result>
        <collection property="emps"
                    select="com.atguigu.mybatis.mapper.DeptMapper.getDeptAndEmpByStepTwo"
                    column="dept_id"></collection>
    </resultMap>
    
    <!--    Dept getDeptAndEmpByStepOne(@Param("deptId") int deptId);
        // 先查出指定id的部门信息,部门信息中有对应员工的dept_id -->
    <select id="getDeptAndEmpByStepOne" resultMap="deptAndEmpResultMapByStep">
        select * from t_dept where dept_id = #{deptId}
    </select>

    <!--    List<Emp> getDeptAndEmpByStepTwo(@Param("deptId") int deptId);
    // 再根据dept_id查出相对应的员工信息-->
    <select id="getDeptAndEmpByStepTwo" resultType="Emp">
        select * from t_emp where dept_id = #{deptId}
    </select>

</mapper>

EmpMapper

xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.mybatis.mapper.EmpMapper">
    <!--
        处理多对一的映射关系
        有三种方法:
        第一种:级联方式处理
        第二种:association 处理多对一的映射关系(处理的是实体类类型的属性)
        第三种:分布查询
    -->

<!-- ************ 第一种:级联方式处理  *************** -->
    <resultMap id="EmpAndDeptById_resultMap" type="Emp">
        <id column="emp_id" property="empId"></id>
        <result column="emp_name" property="empName"></result>
        <result column="age" property="age"></result>
        <result column="gender" property="gender"></result>

        <result column="dept_id" property="dept.deptId"></result>
        <result column="dept_name" property="dept.deptName"></result>
    </resultMap>

    <!--Emp getEmpAndDeptById(@Param("empId") Integer empId);-->
    <select id="getEmpAndDeptById" resultMap="EmpAndDeptById_resultMap">
        select *
        from t_emp
        left join t_dept on t_emp.dept_id = t_dept.dept_id
        where t_emp.emp_id=#{empId}
    </select>

<!-- *********************************************-->

<!-- *************** 第二种 association ******************************-->

    <!--  第二种 association-->
    <resultMap id="getEmpAndDeptById_association_resultMap" type="Emp">
        <id column="emp_id" property="empId"></id>
        <result column="emp_name" property="empName"></result>
        <result column="age" property="age"></result>
        <result column="gender" property="gender"></result>
        <!--
            association: 处理多对一的映射关系(处理实体类类型的属性)
            property: 设置需要处理映射关系的属性的属性名
            javaType: 设置要处理的属性的类型, 就是把<association>标签下设置映射关系的字段,封装给某个类
        -->
        <association property="dept" javaType="Dept">
            <id column="dept_id" property="deptId"></id>
            <result column="dept_name" property="deptName"></result>
        </association>

    </resultMap>

    <!--    Emp getEmpAndDeptById_association(@Param("empId") Integer empId);-->
    <select id="getEmpAndDeptById_association" resultMap="getEmpAndDeptById_association_resultMap">
        select *
        from t_emp
        left join t_dept on t_emp.dept_id = t_dept.dept_id
        where t_emp.emp_id=#{empId}
    </select>


<!-- *********************************************-->

<!-- ****************** 第三种:分布查询 ***************************-->
    <resultMap id="getEmpAndDeptByIdOne_resultMap" type="Emp">
        <id column="emp_id" property="empId"></id>
        <result column="emp_name" property="empName"></result>
        <result column="age" property="age"></result>
        <result column="gender" property="gender"></result>
        <!--
            property: 设置需要处理映射关系的属性的属性名
            select: 填写分步查询的sql的唯一标识,就是设置下一步要执行的sql语句
            column: 将上一个sql查询出的某个字段作为分步查询的下一个sql语句sql条件,相当于函数的参数,传给下一个sql语句
            fetchType: 在开启了延时加载的环境中,通过该属性设置当前的分步查询是否使用延迟加载
                有两个值:eager(立即加载) lazy(延迟加载)
        -->
        <association property="dept"
                     fetchType="eager"
                     select="com.atguigu.mybatis.mapper.EmpMapper.getEmpAndDeptByIdTwo"
                     column="dept_id">
        </association>
    </resultMap>

    <!--    Emp getEmpAndDeptByIdOne(@Param("empId") Integer empId);-->
    <select id="getEmpAndDeptByIdOne" resultMap="getEmpAndDeptByIdOne_resultMap">
        select * from t_emp where emp_id = #{empId}
    </select>

    <!--    Dept getEmpAndDeptByIdTwo(@Param("deptId") Integer deptId);-->
    <select id="getEmpAndDeptByIdTwo" resultType="Dept">
        select * from t_dept where dept_id = #{deptId}
    </select>

<!-- *********************************************-->

</mapper>

ResultMapTest

java 复制代码
import com.atguigu.mybatis.mapper.DeptMapper;
import com.atguigu.mybatis.mapper.EmpMapper;
import com.ruanjian.pojo.Dept;
import com.ruanjian.pojo.Emp;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;

public class ResultMapTest {
    private SqlSession session;

    /*
    处理多对一的映射关系
    有三种方法:
    第一种:级联方式处理
    第二种:association 处理多对一的映射关系(处理的是实体类类型的属性)
    第三种:分步查询
    */


    // *********************** 多对一  ****************************************

    @Test
    // 第三种:分步查询
    public void textGetEmpAndDeptByIdOne() {
        EmpMapper mapper = session.getMapper(EmpMapper.class);
        Emp emp = mapper.getEmpAndDeptByIdOne(1);
        System.out.println(emp);
    }


    @Test
    // 第二种:association
    public void textGetEmpAndDeptById_association() {
        EmpMapper mapper = session.getMapper(EmpMapper.class);
        Emp emp = mapper.getEmpAndDeptById_association(2);
        System.out.println(emp);
    }


    @Test
    // 第一种:级联方式处理
    public void textGetEmpAndDeptById() {
        EmpMapper mapper = session.getMapper(EmpMapper.class);
        Emp emp = mapper.getEmpAndDeptById(2);
        System.out.println(emp);
    }


    // *********************** 一对多  ****************************************

    @Test
    // 分步查询
    public void textGetDeptAndEmpByStep() {
        DeptMapper mapper = session.getMapper(DeptMapper.class);
        Dept dept = mapper.getDeptAndEmpByStepOne(2);
        System.out.println(dept);
    }


    @Test
    // 一对多查询
    public void textGetDeptAndEmpById() {
        DeptMapper mapper = session.getMapper(DeptMapper.class);
        Dept dept = mapper.getDeptAndEmpById(1);
        System.out.println(dept);
    }

    // ***************************************************************


    // junit会在每一个@Test方法前执行@Before方法
    @Before
    public void init() throws IOException {
        session = new SqlSessionFactoryBuilder()
                .build(
                        Resources.getResourceAsStream("mybatis-config.xml"))
                .openSession();
    }

    // junit会在每一个@Test方法后执行@After方法
    @After
    public void clear() {
        session.commit();
        session.close();
    }
}

db.properties

xml 复制代码
mysql.driver=com.mysql.cj.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=false
mysql.username=root
mysql.password=123456

log4j.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

    <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
        <param name="Encoding" value="UTF-8"/>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m  (%F:%L) \n"/>
        </layout>
    </appender>
    <logger name="java.sql">
        <level value="debug"/>
    </logger>
    <logger name="org.apache.ibatis">
        <level value="info"/>
    </logger>
    <root>
        <level value="debug"/>
        <appender-ref ref="STDOUT"/>
    </root>
</log4j:configuration>

mybatis-config.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--环境配置-->
    <!--引入外部db.properties-->
    <properties resource="db.properties"/>

    <settings>
        <!--        <setting name="cacheEnabled" value="true" />-->
        <!--  开启延时加载-->
        <setting name="lazyLoadingEnabled" value="true"/>

        <!-- 开启时即为true时任何方法的调用都会加载相关类的全部属性
        false时是按需加载,true是全部加载
        -->
        <setting name="aggressiveLazyLoading" value="false"/>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    
    <typeAliases>
        <package name="com.ruanjian.pojo"/>
    </typeAliases>

    <!--配置mybatis的连接环境(可以配置多个环境)-->
    <environments default="development">
        <!--开发环境-->
        <environment id="development">
            <!--使用JDBC事务管理-->
            <transactionManager type="JDBC"/>
            <!--数据库连接相关配置,db.properties文件中的内容-->
            <!--使用连接池技术-->
            <dataSource type="POOLED">
                <!--数据库驱动-->
                <property name="driver" value="${mysql.driver}"/>
                <!--连接字符串-->
                <property name="url" value="${mysql.url}"/>
                <!--数据库用户名-->
                <property name="username" value="${mysql.username}"/>
                <!--数据库密码-->
                <property name="password" value="${mysql.password}"/>
            </dataSource>
        </environment>
    </environments>


    <!--mapping文件路径配置-->
    <mappers>
        <!--        <mapper resource="mapper/DeptMapper.xml"/>-->
        <package name="com.atguigu.mybatis.mapper"/>
    </mappers>
</configuration>

pom.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.itheima</groupId>
    <artifactId>MyBaits_2</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <properties>
        <maven.compiler.sourece>11</maven.compiler.sourece>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>


    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.11</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>text</scope>
        </dependency>
        <!-- log4j日志 -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>
</project>

注意

新建包时用点

例如:com.atguigu.mybatis.mapper

resources目录下建立多层目录的时候时是用分割线

例如:com/atguigu/mybatis/mapper

mybatis-config.xml文件中

bash 复制代码
<package name="com.atguigu.mybatis.mapper"/>

<package>的使用条件:

接口文件要和xml文件同名,并且在同一个目录下

使用注解写的接口,只能有class的方式注册,例:

bash 复制代码
<mapper class="com.atguigu.mybatis.mapper.DeptMapper"></mapper>
相关推荐
小桥流水人家jjh2 小时前
Mybatis执行自定义SQL并使用PageHelper进行分页
java·数据库·spring boot·sql·mybatis
黑马师兄3 小时前
Mybatis
java·mybatis
Neoest1 天前
场景解决之mybatis当中resultType= map时,因某个字段为null导致返回的map的key不存在怎么处理
mybatis
ZWZhangYu1 天前
【MyBatis源码】深入分析TypeHandler原理和源码
数据库·oracle·mybatis
小鸡脚来咯2 天前
springboot 整合mybatis
java·spring boot·mybatis
种树人202408192 天前
MyBatis xml 文件中 SQL 语句的小于号未转义导致报错
mybatis
码农派大星。2 天前
MyBatis操作--进阶
mybatis
爱读源码的大都督2 天前
MyBatis中的LanguageDriver的作用是什么
java·spring boot·mybatis
鹿屿二向箔2 天前
基于SSM(Spring + Spring MVC + MyBatis)框架的快递管理系统
spring·mvc·mybatis
2的n次方_2 天前
MyBatis——增删查改(XML 方式)
xml·数据库·mybatis