mybatis复习04高级查询 一对多,多对一的映射处理,collection和association标签的使用

简介: 文章介绍了MyBatis中高级查询的一对多和多对一映射处理,包括创建数据库表、抽象对应的实体类、使用resultMap中的association和collection标签进行映射处理,以及如何实现级联查询和分步查询。此外,还补充了延迟加载的设置和用法。

一对多,和多对一之间的关系。比如,当前有一个实体类为员工类,还有一个实体类为部门类,那么由日常生活便能看出他们之间的关系,一个员工只属于一个部门,然后一个部门包括多个员工。

创建数据库表 员工和部门

员工表 t_emp:
在这里插入图片描述
部门表t_dept:
在这里插入图片描述
填充一些测试的数据:
在这里插入图片描述
在这里插入图片描述

抽象对应的实体类

员工实体类

由一开始的分析得出,员工类应包含员工个人的基本信息,以及对应部门的基本信息。所以在员工类中,应包含部门这一属性,部门也是一个单独的对象,包括部门号和部门名称。
确定了类中的基本属性后,为其添加对应的构造器,这里需要注意的是,员工类的构造器应只具备其员工个人基本属性的构造器,然后添加对应的getter和setter方法以及重写toString方法。

package com.gothic.sunset.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 +
                '}';
    }
}

部门实体类

部门实体类应包括部门的基本信息和每个部门中所有员工的信息。同理,其构造器也需要注意,只具备部门基本信息的构造器。

package com.gothic.sunset.pojo;

import java.util.List;

public class Dept {
   
    private Integer deptId;//部门id号

    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 +
                '}';
    }
}

多对一的映射处理

级联方式resultMap自定义映射处理

需求:根据员工id,查询员工的所有信息(包括他的基本信息和对应的部门信息)。
首先,在mapper接口中编写对应的方法:

    /**
     * 根据id查询员工信息
     * @param empId
     * @return
     */
    Emp getEmpByEmpId(@Param("empId") Integer empId);

在映射文件xml中编写对应的sql:

    <resultMap id="getEmpAllByEmpId" 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 getEmpByEmpId(@Param("empId") Integer empId);-->
    <select id="getEmpByEmpId" resultMap="getEmpAllByEmpId">
        select
            t_emp.*,t_dept.*
        from t_emp
                 inner join t_dept
                           on t_emp.dept_id = t_dept.dept_id
        where t_emp.emp_id = #{empId}
    </select>

这里通过使用resultMap自定义映射关系来将一对多映射处理,然后sql的话使用两表内连接查询。
测试用例:

    @Test
    public void testGetEmpByEmpIdList(){
   
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        Emp emp = mapper.getEmpByEmpId(1);
        System.out.println(emp);
    }

输出:
在这里插入图片描述

使用resultMap中的association标签

association标签级联查询

association:处理多对一的映射关系。
association标签的结构:

  • property:需要处理多对一的映射关系的属性名
  • javaType:该属性的类型
        <association property="" javaType="" ......>
            <id property="" column=""></id>
            <result property="" column=""></result>
        </association>

其中association的属性还包括很多,下图是association标签中的属性:
在这里插入图片描述
在mapper接口中编写一个新的根据id查询的方法:

    /**
     * 根据id查询员工信息 使用association标签 级联查询
     * @param empId
     * @return
     */
    Emp getEmpByEmpIdTwo(@Param("empId") Integer empId);

在映射文件xml中编写对应的sql:

    <resultMap id="getEmpAllByEmpIdTwo" 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="dept" javaType="Dept" >
            <id  column="dept_id" property="deptId"></id>
            <result  column="dept_name" property="deptName"></result>
        </association>
    </resultMap>
    <!--Emp getEmpByEmpIdTwo(@Param("empId") Integer empId);-->
    <select id="getEmpByEmpIdTwo" resultMap="getEmpAllByEmpIdTwo">
        select
            t_emp.*,t_dept.*
        from t_emp
                 inner join t_dept
                            on t_emp.dept_id = t_dept.dept_id
        where t_emp.emp_id = #{empId}
    </select>

测试用例:

    @Test
    public void testGetEmpByEmpIdListTwo(){
   
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        Emp emp = mapper.getEmpByEmpIdTwo(1);
        System.out.println(emp);
    }

输出:
在这里插入图片描述

association标签分步查询

分步查询,涉及到association标签的另外两个属性:

  • select:设置分布查询的sql的唯一标识(namespace.SQLId或mapper接口的全类名.方法名)
  • column:设置分步查询的条件

同样编写一个新的mapper接口中的方法,来进行测试:

     /**
     * 根据id查询员工信息 使用association标签 分步查询
     * @param empId
     * @return
     */
    Emp getEmpByEmpIdThree(@Param("empId") Integer empId);

在映射文件xml中编写对应的sql:

    <resultMap id="getEmpAndDeptByStepMap" 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  column="dept_id" property="dept" select="com.gothic.sunset.mapper.EmpMapper.getEmpAndDeptByStepTwo" >
        </association>
    </resultMap>
    <!-- Emp getEmpAndDeptByStepOne(@Param("empId") Integer empId);-->
    <select id="getEmpAndDeptByStepOne" resultMap="getEmpAndDeptByStepMap">
        select * from t_emp where emp_id = #{empId}
    </select>


    <resultMap id="getEmpAndDeptByStepTwoMap" type="Dept">
        <id column="dept_id" property="deptId"></id>
        <result column="dept_name" property="deptName"></result>
    </resultMap>
    <!--Dept getEmpAndDeptByStepTwo(@Param("deptId") Integer deptId);-->
    <select id="getEmpAndDeptByStepTwo" resultMap="getEmpAndDeptByStepTwoMap">
        select * from t_dept where dept_id = #{deptId}
    </select>

测试用例:

    @Test
    public void getEmpAndDeptByStep(){
   
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        Emp emp = mapper.getEmpAndDeptByStepOne(1);
        System.out.println(emp);
    }

输出:
在这里插入图片描述

一对多的映射处理

resultMap中的collection标签

collection:
collection:用来处理一对多的映射关系

  • property:需要处理一对多的映射关系的属性名
  • ofType:表示该属性对应的集合中存储的数据的类型
    其完整的参数列表:
    在这里插入图片描述

需求:根据部门id查询部门中的所有员工。

collection标签级联查询

首先,在mapper接口中编写对应的方法:
这里,根据id查询部门表返回所有的员工及部门信息,返回值应该是一个list而且其泛型要遵循Dept类的约束(思考一下就会明白,为什么不是遵循Emp类的约束)。

     /**
     * 根据部门id查询所有员工信息
     * @param deptId
     * @return
     */
    List<Dept> getDeptAndEmpById(Integer deptId);

在映射文件xml中编写对应的sql:

    <resultMap id="getDeptAndEmpMap" type="Dept">
        <id property="deptId" column="dept_id"></id>
        <result property="deptName" column="dept_name"></result>
        <collection property="emps" ofType="Emp">
            <id property="empId" column="emp_id"></id>
            <result property="empName" column="emp_name"></result>
            <result property="age" column="age"></result>
            <result property="sex" column="sex"></result>
            <result property="email" column="email"></result>
        </collection>
    </resultMap>
    <!--List<Dept> getDeptAndEmpById(Integer deptId);-->
    <select id="getDeptAndEmpById" resultMap="getDeptAndEmpMap">
        select * from t_dept left join t_emp on t_dept.dept_id = t_emp.emp_id where t_dept.dept_id = #{dept_id}
    </select>

测试用例:

    @Test
    public void getDeptAndEmpById(){
   
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
        List<Dept> emps = mapper.getDeptAndEmpById(1);
        emps.forEach(System.out::println);
    }

输出:
在这里插入图片描述

collection标签分步查询

分步查询可以分为两步:

  • 分步查询第一步:查询部门信息
  • 分步查询第二步:根据部门id查询部门中的所有员工
    在mapper接口中编写对应的新方法:
     /**
     * 通过分步查询,查询部门及对应的所有员工信息
     * 分步查询第一步:查询部门信息
     * @param deptId
     * @return
     */
    Dept getDeptAndEmpByStepOne(@Param("deptId") Integer deptId);

    /**
     * 通过分步查询,查询部门及对应的所有员工信息
     * 分步查询第二步:根据部门id查询部门中的所有员工
     * @param empId
     * @return
     */
    List<Emp> getDeptAndEmpByStepTwo(@Param("empId") Integer empId);

在映射文件xml中编写对应的sql:

<resultMap id="getDeptAndEmpByStepOneMap" type="Dept">
        <id property="deptId" column="dept_id"></id>
        <result property="deptName" column="dept_name"></result>
        <collection property="emps"
                    select="com.gothic.sunset.mapper.DeptMapper.getDeptAndEmpByStepTwo"
                    column="dept_id">
        </collection>
    </resultMap>
    <!--Dept getDeptAndEmpByStepOne(@Param("deptId") Integer deptId);-->
    <select id="getDeptAndEmpByStepOne" resultMap="getDeptAndEmpByStepOneMap">
        select * from t_dept where dept_id = #{deptId}
    </select>

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

测试用例:
这里因为我是恰好部门id为1的员工只有一条数据,所以就这样写了。大家如果单纯为了查看是否正常可以不输出,从DEBUG中就可以看到。

    @Test
    public void getDeptAndEmpByStrp(){
   
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
        Dept emps =  mapper.getDeptAndEmpByStepOne(1);
        System.out.println(emps);
    }

输出:
在这里插入图片描述

补充延迟加载

分步查询的优点:可以实现延迟加载,但是必须在核心配置文件中设置全局配置信息:

  • lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载
  • aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。 否则,每个属性会按需加载
    此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。此时可通过association和collection中的fetchType属性设置当前的分步查询是否使用延迟加载,fetchType=“lazy(延迟加载)|eager(立即加载)”.
<settings>
    <!--开启延迟加载-->
    <setting name="lazyLoadingEnabled" value="true"/>
</settings>

fetchType:当开启了全局的延迟加载之后,可以通过该属性手动控制延迟加载的效果,fetchType="lazy(延迟加载)|eager(立即加载),它作用于collection和association标签上。
可以自行思考一下,开启延迟加载后的状况。
今天的复习结束啦!!!!
在这里插入图片描述

相关文章
|
1天前
|
XML Java 数据库连接
Mybatis实现RBAC权限模型查询
通过对RBAC权限模型的理解和MyBatis的灵活使用,我们可以高效地实现复杂的权限管理功能,为应用程序的安全性和可维护性提供有力支持。
14 5
|
20天前
|
SQL Java 数据库连接
spring和Mybatis的各种查询
Spring 和 MyBatis 的结合使得数据访问层的开发变得更加简洁和高效。通过以上各种查询操作的详细讲解,我们可以看到 MyBatis 在处理简单查询、条件查询、分页查询、联合查询和动态 SQL 查询方面的强大功能。熟练掌握这些操作,可以极大提升开发效率和代码质量。
32 3
|
1月前
|
SQL 安全 Java
MyBatis-Plus条件构造器:构建安全、高效的数据库查询
MyBatis-Plus 提供了一套强大的条件构造器(Wrapper),用于构建复杂的数据库查询条件。Wrapper 类允许开发者以链式调用的方式构造查询条件,无需编写繁琐的 SQL 语句,从而提高开发效率并减少 SQL 注入的风险。
30 1
MyBatis-Plus条件构造器:构建安全、高效的数据库查询
|
2月前
|
SQL Java 数据库连接
mybatis如何仅仅查询某个表的几个字段
【10月更文挑战第19天】mybatis如何仅仅查询某个表的几个字段
80 1
|
2月前
|
SQL XML Java
Mybatis的<where>,<if>等标签用法
这篇文章详细解释了Mybatis中<where>和<if>等标签的用法,展示了如何在SQL动态构建中有效地过滤条件和处理逻辑分支。
256 1
|
2月前
|
SQL Java 数据库连接
Mybatis入门(select标签)
这篇文章介绍了Mybatis中`select`标签的基本用法及其相关属性,并通过示例展示了如何配置和执行SQL查询语句。
52 0
Mybatis入门(select标签)
|
2月前
|
SQL Java 数据库连接
Mybatis的<insert>,<update>,<delete>标签用法
这篇文章详细讲解了Mybatis中<insert>, <update>, <delete>标签的使用方法,并提供了示例代码来展示如何执行数据库的增删改操作。
107 0
|
2月前
|
Java 数据库连接 Maven
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和MyBatis Generator,使用逆向工程来自动生成Java代码,包括实体类、Mapper文件和Example文件,以提高开发效率。
145 2
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
|
2月前
|
SQL JSON Java
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和PageHelper进行分页操作,并且集成Swagger2来生成API文档,同时定义了统一的数据返回格式和请求模块。
75 1
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
|
2月前
|
前端开发 Java Apache
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
本文详细讲解了如何整合Apache Shiro与Spring Boot项目,包括数据库准备、项目配置、实体类、Mapper、Service、Controller的创建和配置,以及Shiro的配置和使用。
508 1
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
下一篇
DataWorks