第九节:mybatis关联查询之一对多查询(代码片段)

ye-feng-yu ye-feng-yu     2022-12-20     192

关键词:

一对多,是最常见的一种设计。就是 A 表的一条记录,对应 B 表的多条记录,且 A 的主键作为 B 表的外键。这主要看以哪张表为中心,下面的测试数据中,从employee 表来看,一个员工对应一个部门,是一对一关系,如果从部门角度来看,则是一对多的关系,一个部门对应多个员工,本节主要研究一对多的关系。

查询部门的时候将部门对应的所有员工信息也查询出来

1,数据表建立


新建数据表department,有两个字段,插入两条数据如下:

id dept_name
1 CIA
2 FSB

新建数据表employee,有三个字段,其中dept_id是外键,关联department表的主键id。插入数据如下:

id last_name dept_id
1 Tom 1
2 Jerry 2
3 Neo 1
4 Cypher 2

2,新建maven工程,添加依赖,主要是mybatis和mysql


<dependencies>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.6</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>
</dependencies>

3、编写数据库表对应的实体。


对于department表,对应实体如下:注意增加一个包含了Employee集合。

package com.yefengyu.mybatis.entity;

import java.util.List;


public class Department

    private Integer id;

    private String deptName;

    private List<Employee> employees;

    public Integer getId()
    
        return id;
    

    public void setId(Integer id)
    
        this.id = id;
    

    public String getDeptName()
    
        return deptName;
    

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

    public List<Employee> getEmployees()
    
        return employees;
    

    public void setEmployees(List<Employee> employees)
    
        this.employees = employees;
    

    @Override
    public String toString()
    
        return "Department" +
               "id=" + id +
               ", deptName=‘" + deptName + ‘\‘‘ +
               ", employees=" + employees +
               ‘‘;
    

对于employee表,实体如下,注意在Employee实体中把外键直接变成对于Department对象的引用。

package com.yefengyu.mybatis.entity;

public class Employee

    private Integer id;

    private String lastName;

    private Department department;

    public Integer getId()
    
        return id;
    

    public void setId(Integer id)
    
        this.id = id;
    

    public String getLastName()
    
        return lastName;
    

    public void setLastName(String lastName)
    
        this.lastName = lastName;
    

    public Department getDepartment()
    
        return department;
    

    public void setDepartment(Department department)
    
        this.department = department;
    

    @Override
    public String toString()
    
        return "Employee" +
               "id=" + id +
               ", lastName=‘" + lastName + ‘\‘‘ +
               ", department=" + department +
               ‘‘;
    

4、编写mapper接口


package com.yefengyu.mybatis.mapper;

import com.yefengyu.mybatis.entity.Department;


public interface DepartmentMapper

    public Department getDeptById(Integer id);

根据部门ID查询部门信息和对应的所有员工信息。

5、编写mapper映射文件(本节重点


collection嵌套结果集方法:
<?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.yefengyu.mybatis.mapper.DepartmentMapper">
    <resultMap id="dept" type="com.yefengyu.mybatis.entity.Department">
        <id column="d_id" property="id"/>
        <result column="dept_name" property="deptName"/>
        <!--
         collection定义关联集合类型的属性的封装规则
           ofType:指定集合里面元素的类型
          -->
        <collection property="employees" ofType="com.yefengyu.mybatis.entity.Employee" javaType="java.util.ArrayList">
            <id column="id" property="id"/>
            <result column="last_name" property="lastName"/>
        </collection>
    </resultMap>
    <select id="getDeptById" resultMap="dept">
        select e.id id, e.last_name last_name, e.dept_id dept_id, d.id d_id,d.dept_name dept_name
        from department d
        left join employee e
        on e.dept_id = d.id
        where d.id = #id 
    </select>
</mapper>

6、新建一个mybatis全局配置文件,详细信息见官网


<?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>
    <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="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?characterEncoding=utf8&amp;allowMultiQueries=true"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mapper/DepartmentMapper.xml"/>
    </mappers>
</configuration>

7、测试


public static void main(String[] args)
    throws IOException

    InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
    SqlSession sqlSession = sqlSessionFactory.openSession();
    try
    
        DepartmentMapper mapper = sqlSession.getMapper(DepartmentMapper.class);
        Department dept = mapper.getDeptById(1);
        System.out.println(dept);
    
    finally
    
        sqlSession.close();
    

结果如下:

Created connection 1938056729.
Setting autocommit to false on JDBC Connection [[email protected]]
==>  Preparing: select e.id id, e.last_name last_name, e.dept_id dept_id, d.id d_id,d.dept_name dept_name from department d left join employee e on e.dept_id = d.id where d.id = ? 
==> Parameters: 1(Integer)
<==    Columns: id, last_name, dept_id, d_id, dept_name
<==        Row: 1, Tom, 1, 1, CIA
<==        Row: 3, Neo, 1, 1, CIA
<==      Total: 2
Departmentid=1, deptName=‘CIA‘, employees=[Employeeid=1, lastName=‘Tom‘, department=null, Employeeid=3, lastName=‘Neo‘, department=null]
Resetting autocommit to true on JDBC Connection [[email protected]]
Closing JDBC Connection [[email protected]73846619]

上面查询虽然可以查询出数据,但是数据过多则会有性能问题,因此好的做法是分步查询。

8,分步查询


1、新增查询员工的接口,特别注意是根据部门id来查询

package com.yefengyu.mybatis.mapper;

import com.yefengyu.mybatis.entity.Employee;


public interface EmployeeMapper

    Employee getEmpByDeptId(Integer deptId);

2、编写对应的mapper映射文件

<?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.yefengyu.mybatis.mapper.EmployeeMapper">
    <select id="getEmployee" resultType="com.yefengyu.mybatis.entity.Employee">
        select * from employee where dept_id = #id
    </select>
</mapper>

3、编写查询部门的接口

package com.yefengyu.mybatis.mapper;

import com.yefengyu.mybatis.entity.Department;


public interface DepartmentMapper

    public Department getDeptById(Integer id);

4、编写对应的映射文件

<?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.yefengyu.mybatis.mapper.DepartmentMapper">
    <resultMap id="dept" type="com.yefengyu.mybatis.entity.Department">
        <id column="id" property="id"/>
        <result column="dept_name" property="deptName"/>
        <!-- 扩展:多列的值传递过去:
               将多列的值封装map传递:column="key1=column1,key2=column2"
             fetchType="lazy":表示使用延迟加载;
                      - lazy:延迟
                      - eager:立即
        -->
        <collection property="employees" select="com.yefengyu.mybatis.mapper.EmployeeMapper.getEmployee"
                    column="id" fetchType="lazy">
        </collection>
    </resultMap>
    <select id="getDeptById" resultMap="dept">
        select id ,dept_name from department where id = #id
    </select>
</mapper>

5、测试结果

Created connection 1694556038.
Setting autocommit to false on JDBC Connection [[email protected]]
==>  Preparing: select id ,dept_name from department where id = ? 
==> Parameters: 1(Integer)
<==    Columns: id, dept_name
<==        Row: 1, CIA
<==      Total: 1
==>  Preparing: select * from employee where dept_id = ? 
==> Parameters: 1(Integer)
<==    Columns: id, last_name, dept_id
<==        Row: 1, Tom, 1
<==        Row: 3, Neo, 1
<==      Total: 2
Departmentid=1, deptName=‘CIA‘, employees=[Employeeid=1, lastName=‘Tom‘, department=null, Employeeid=3, lastName=‘Neo‘, department=null]
Resetting autocommit to true on JDBC Connection [[email protected]]
Closing JDBC Connection [[email protected]]

如果测试代码的打印改为:

System.out.println(dept.getDeptName());

那么结果如下,不会查询员工信息。

Created connection 1694556038.
Setting autocommit to false on JDBC Connection [[email protected]]
==>  Preparing: select id ,dept_name from department where id = ? 
==> Parameters: 1(Integer)
<==    Columns: id, dept_name
<==        Row: 1, CIA
<==      Total: 1
CIA
Resetting autocommit to true on JDBC Connection [[email protected]]
Closing JDBC Connection [[email protected]]
Returned connection 1694556038 to pool.

9、全局配置与局部配置


1、全局配置

lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。
默认值:false

aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。 否则,每个属性会按需加载(参考 lazyLoadTriggerMethods)。
默认值:false (在 3.4.1 及之前的版本默认值为 true),现在新版本可以不用关注此设置。

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

2、局部配置fetchType

<association property="" fetchType="eager"></association>
<collection property="" fetchType="lazy"></collection>
 
  • lazy:延迟
  • eager:立即

3、区别(查询部门信息,不查看员工信息时)

全局 局部 是否延迟
不开启 不开启
不开启 lazy
不开启 eager
开启 不开启
开启 lazy
开启 eager

mybatis学习09高级映射之一对多查询

上一篇博文总结了一下一对一的映射,本文主要总结一下一对多的映射,从上一篇文章中的映射关系图中可知,订单项和订单明细是一对多的关系,所以本文主要来查询订单表,然后关联订单明细表,这样就有一对多的问题出来... 查看详情

mybatis-记录(代码片段)

文章目录MyBatis一对多关联查询MyBatis一对多关联查询样例MyBatis多对多关联查询文章目录JavaJavaMyBatis一对多关联查询在MyBatis中,通过<resultMap>元素的子元素<collection>处理一对多级联关系,collection可以将关联查询的... 查看详情

mybatis关联查询,一对多关联查询

实体关系图,一个国家对应多个城市一对多关联查询可用三种方式实现:单步查询,利用collection标签为级联属性赋值;分步查询:利用association标签进行分步查询;利用collection标签进行分步查询单步查询利用collection标签实现一... 查看详情

mybatis注解开发之一对多查询(代码片段)

文章目录0.MyBatis的注解实现复杂映射开发1.一对多查询1.1一对多查询的模型1.2一对多查询的语句1.3创建StudentMapper接口1.4使用注解配置Mapper1.5测试类1.6一对多配置总结0.MyBatis的注解实现复杂映射开发实现复杂关系映射之前我们可以... 查看详情

mybatis4——一对一对多关联查询

关联查询:一对一:1、业务扩展类  核心:用resultType指定的类的属性包含多表查询的所有字段。2、resultMap  通过添加属性成员建立两个类之间的连接<!--利用resultMap实现一对一 -->    <selecti... 查看详情

mybatis多表查询(一对多,多对一,多对多)(代码片段)

Mybatis多表查询1、一对多1.1、用户详情1.2、用户订单1.3、关联2、多对一2.1通过id查询订单详情2.2关联3、多对多3.1、查询所有学生3.2、查询指定学生的所有授课老师1、一对多查询用户详情,同时查询到用户管理的所有订单查询... 查看详情

mybatis高级篇-关联查询(一对多)

...可以下多个订单,所以,它们的关系是一对多关联关系。MyBatis实现一对多采用的是<resultMap>,在<resultMap>里面用<collection>子标签配置多方信息。我们想查询所有用户及其订单信息,一个用户可以下若多个订单。SQL语... 查看详情

java--mybatis关联映射之关联单个对象(即一对一);关联多个对象(即一对多)(代码片段)

使用Mybatis框架,在业务需要对数据库进行关联查询的时候需使用关联映射而关联映射分为关联单个对象与关联多个对象,即一对一、一对多的情况,且每种关联方式都可以有两种处理情况,即使用1条sql进行处理... 查看详情

mybatis的关联查询(一对一,一对多)

一.一对一  举个例子:  实体类:User    privateIntegerid;     private Stringname;     private Integerage;     private Stringsex;    get/set方法省略  Mapper.xml文件中定义查询语句  <mappernamespace="">... 查看详情

mybatis之关联查询和缓存(代码片段)

...ff1a;一般对应数据库中该行的主键id,设置此项可提高MyBatis性能result:映射到JavaBean的某个“简单类型”属性association:映射到JavaBea 查看详情

mybatis关联查询一对一和一对多的实现

Mybatis一对一关联查询有两张表,老师表teacher和班级表class,一个class班级对应一个teacher,一个teacher对应一个class需求是根据班级id查询班级信息(带老师的信息)创建teacher和class表:CREATETABLEteacher(t_idINTPRIMARYKEYAUTO_INCREMENT,t_nameVARCHAR... 查看详情

mybatis一对多查询及延迟加载

...查询的结果集存储在User对象的上哪个属性。ofType="com.demo.mybatis.po.Order":指定关联查询的结果集中的对象类型即List中的对象类型。此处可以使用别名,也可以使用全限定名。MyBatis根据关联对象查询的select的语句的执行时机,分... 查看详情

mybatis一对多关联表查询映射文件

<!--一对多--><!--根据广告组编号获取广告项列表一--><selectid="getAdInfoByAdSysNo"resultType="ec.model.advertising.AdInfo"parameterType="int">SELECT*FROMT_AD_ADINFOWHEREadSysNo=#{sysNo,jdbcType=INTEGER} 查看详情

学习mybatis(代码片段)

文章目录MyBatis搭建核心配置文件数据库环境配置属性设置设置setting类型别名其它配置项逆向工程创建逆向工程使用逆向工程动态SQLMyBatis查询一对一关联查询一对多关联查询多对多关联查询分页查询方案一:使用Page工具类方案二:... 查看详情

mybatis中如何实现一对一,一对多的关联查询?(代码片段)

MyBatis实现一对一、一对多关联查询一般有两种方式:方式一:sqlMapper配置文件一对一:在resultMap标签中使用association标签一对多:在resultMap标签中使用collection 标签方式二:注解一对一:在@Results 注解... 查看详情

mybatis-关联查询

了解关联查询中的关系●数据库表的关联查询:一对一,一对多,多对多①一对一:是通过在任意一方的主键,引入对方主键作为外键来实现的,就是说主键与外键为同一字段②一对多:是通过在“多”的一方,添加“... 查看详情

mybatis--表关系之一对多

mybatis中的多表查询表关系分类:  一对一  多对一(一对多)  多对多一对多  示例:一个用户有多个社会角色,      我们需要两张表,m_user和m_role表,需要在角色表上面添加用户表的外键     &n... 查看详情

mybatis高级篇-关联查询(一对一)

...一个一对一的简单模型,一张订单只能对应一个用户。在MyBatis中,一对一可以用<resultType>或<resultMap>对结果进行映射。我们要查找所有的订单信息,以及该订单下的用户信息。每个订单对应一个用户,订单与用户之间通... 查看详情