第九节:mybatis关联查询之一对多查询

一对多,是最常见的一种设计。就是 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
Department{id=1, deptName=‘CIA‘, employees=[Employee{id=1, lastName=‘Tom‘, department=null}, Employee{id=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
Department{id=1, deptName=‘CIA‘, employees=[Employee{id=1, lastName=‘Tom‘, department=null}, Employee{id=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

原文地址:https://www.cnblogs.com/ye-feng-yu/p/11042924.html

时间: 2024-10-16 16:49:20

第九节:mybatis关联查询之一对多查询的相关文章

mybatis 关联(多表)查询

一对一查询 使用resultType: 使pojo类继承一个表对应的javabean,添加另一个表的javabean属性.Xml配置和普通pojo是一样的 使用resultMap: 使pojo添加另一个表对象的javabean属性. Xml配置中使用<association property="user"javaType="user路径">标签配置 association 配置一个关联的对象. 一对多查询 使用resultMap(简单,推荐): pojo

MyBatis关联查询、多条件查询

1.一对一查询 任务需求; 根据班级的信息查询出教师的相关信息 1.数据库表的设计 班级表: 教师表: 2.实体类的设计 班级表: public class Classes { 9     //定义实体类的属性,与class表中的字段对应 10     private int id;            //id===>c_id 11     private String name;    //name===>c_name 13     /** 14      * class表中有一个tea

MyBatis关联查询 (association) 时遇到的某些问题/mybatis映射

先说下问题产生的背景: 最近在做一个用到MyBatis的项目,其中有个业务涉及到关联查询,我是将两个查询分开来写的,即嵌套查询,个人感觉这样更方便重用: 关联的查询使用到了动态sql,在执行查询时就出现了如下错误:Caused by: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'id' in 'class java.lang.Integer' 因为出现了这个问题,

MyBatis关联查询

首先在数据库bookstore中建立三张表,分别是BSuser,author,reader CREATE TABLE `author` (   `id` int(11) NOT NULL AUTO_INCREMENT,   `realName` varchar(20) COLLATE utf8_bin DEFAULT NULL,   `userID` int(11) DEFAULT NULL,   `IDCard` varchar(20) COLLATE utf8_bin DEFAULT NUL

Mybatis关联查询(转载)

原文地址: http://www.cnblogs.com/xiaolang8762400/p/7399892.html mybatis 提供了高级的关联查询功能,可以很方便地将数据库获取的结果集映射到定义的Java Bean 中.下面通过一个实例,来展示一下Mybatis对于常见的一对多和多对一关系复杂映射是怎样处理的. 设计一个简单的博客系统,一个用户可以开多个博客,在博客中可以发表文章,允许发表评论,可以为文章加标签.博客系统主要有以下几张表构成: Author表:作者信息表,记录作者的信息

myBatis --关联查询

业务需求,需要查询到的结果集如下 结构分析 1.查询出所有的评论,即data[]里面是一个list 2.查出list中每个评论id(即userObjectCmmtId)下面所有的子评论,即一对多的关系. 实现方法如下 1.接口层文件如下 2.实现层文件如下 3.返回第一层bean如下 返回第二层bean 4.xml文件如下(第一层)    <resultMap type="com.zhiji.caren.VO.CmmtRel" id="cmmtListMap"

mybatis关联查询问题(一对多、多对一)

mybatis 提供了高级的关联查询功能,可以很方便地将数据库获取的结果集映射到定义的Java Bean 中.下面通过一个实例,来展示一下Mybatis对于常见的一对多和多对一关系复杂映射是怎样处理的. 设计一个简单的博客系统,一个用户可以开多个博客,在博客中可以发表文章,允许发表评论,可以为文章加标签.博客系统主要有以下几张表构成: Author表:作者信息表,记录作者的信息,用户名和密码,邮箱等. Blog表   :  博客表,一个作者可以开多个博客,即Author和Blog的关系是一对多.

Spring+SpringMVC+MyBatis深入学习及搭建(六)——MyBatis关联查询(转发同上)

原地址:http://www.cnblogs.com/shanheyongmu/p/7122520.html 1.商品订单数据模型 1.1数据模型分析思路 (1)每张表记录的数据内容 分模块对每张表记录的内容进行熟悉,相当于你学习系统需求(功能)的过程. (2)每张表重要的字段设置 非空字段.外键字段 (3)数据库级别表与表之间的关系 外键关系 (4)表与表之间的业务关系 在分析表与表之间的业务关系时,一定要建立在某个业务意义基础上去分析. 1.2属性模型分析 2.一对一查询 2.1需求 查询订

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

注:这篇文章的代码有部分删减,不能直接使用,不过关键代码都存在  应用场景: 想用mybatis做关联查询,并且把查询出的数据自动组装成对象可以使用关联查询. 1.一对一实现 例如:一部小说,属于一个分类,查询小说的时候想同时查询出所属分类. 1)实体定义: public class Book { private static final long serialVersionUID = 1L; /** *小说ID */ private Integer bookId; /** *作者 */ pri