mybatis关联查询之一对多查询
一对多,是最常见的一种设计。就是 A 表的一条记录,对应 B 表的多条记录,且 A 的主键作为 B 表的外键。这主要看以哪张表为中心,下面的测试数据中,从employee 表来看,一个员工对应一个部门,是一对一关系,如果从部门角度来看,则是一对多的关系,一个部门对应多个员工,本节主要研究一对多的关系。
查询部门的时候将部门对应的所有员工信息也查询出来
数据表建立
新建数据表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 |
新建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>
编写数据库表对应的实体。
对于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 +
'}';
}
}
编写mapper接口
package com.yefengyu.mybatis.mapper; import com.yefengyu.mybatis.entity.Department; public interface DepartmentMapper
{
public Department getDeptById(Integer id);
}
根据部门ID查询部门信息和对应的所有员工信息。
编写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>
新建一个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&allowMultiQueries=true"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/DepartmentMapper.xml"/>
</mappers>
</configuration>
测试
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 [com.mysql.jdbc.JDBC4Connection@73846619]
==> 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 [com.mysql.jdbc.JDBC4Connection@73846619]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@73846619]
上面查询虽然可以查询出数据,但是数据过多则会有性能问题,因此好的做法是分步查询。
分步查询
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 [com.mysql.jdbc.JDBC4Connection@6500df86]
==> 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 [com.mysql.jdbc.JDBC4Connection@6500df86]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@6500df86]
如果测试代码的打印改为:
System.out.println(dept.getDeptName());
那么结果如下,不会查询员工信息。
Created connection 1694556038.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@6500df86]
==> 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 [com.mysql.jdbc.JDBC4Connection@6500df86]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@6500df86]
Returned connection 1694556038 to pool.
全局配置与局部配置
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关联查询之一对多查询的更多相关文章
- Mybatis关联查询和数据库不一致问题分析与解决
Mybatis关联查询和数据库不一致问题分析与解决 本文的前提是,确定sql语句没有问题,确定在数据库中使用sql和项目中结果不一致. 在使用SpringMVC+Mybatis做多表关联时候,发现也不 ...
- MyBatis关联查询 (association) 时遇到的某些问题/mybatis映射
先说下问题产生的背景: 最近在做一个用到MyBatis的项目,其中有个业务涉及到关联查询,我是将两个查询分开来写的,即嵌套查询,个人感觉这样更方便重用: 关联的查询使用到了动态sql,在执行查询时就出 ...
- mybatis关联查询,一对一,一对多
注:这篇文章的代码有部分删减,不能直接使用,不过关键代码都存在 应用场景: 想用mybatis做关联查询,并且把查询出的数据自动组装成对象可以使用关联查询. 1.一对一实现 例如:一部小说,属于一个 ...
- Spring+SpringMVC+MyBatis深入学习及搭建(六)——MyBatis关联查询
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6923464.html 前面有将到:Spring+SpringMVC+MyBatis深入学习及搭建(五)--动 ...
- MyBatis基础:MyBatis关联查询(4)
1. MyBatis关联查询简介 MyBatis中级联分为3中:association.collection及discriminator. ◊ association:一对一关联 ◊ collecti ...
- MyBatis关联查询,一对多关联查询
实体关系图,一个国家对应多个城市 一对多关联查询可用三种方式实现: 单步查询,利用collection标签为级联属性赋值: 分步查询: 利用association标签进行分步查询: 利用collect ...
- mybatis 关联查询实现一对多
场景:最近接到一个项目是查询管理人集合 同时每一个管理人还存在多个出资人 要查询一个管理人列表 每个管理人又包含了出资人列表 采用mybatis关联查询实现返回数据. 实现方式: 1 .在实体 ...
- MyBatis关联查询、多条件查询
MyBatis关联查询.多条件查询 1.一对一查询 任务需求; 根据班级的信息查询出教师的相关信息 1.数据库表的设计 班级表: 教师表: 2.实体类的设计 班级表: public class Cla ...
- Mybatis关联查询<association> 和 <collection>
一.背景 1.在系统中一个用户存在多个角色,那么如何在查询用户的信息时同时把他的角色信息查询出来啦? 2.用户pojo: public class SysUser { private Long id; ...
- Mybatis关联查询之二
Mybatis关联查询之多对多 多对多 一.entity实体类 public class Student { private Integer stuid; private String stuname ...
随机推荐
- git-ssh-keygen
ssh-keygen 先看本地是否已经有了密钥 cd ~/.ssh 该文件夹下会包含两个文件 id_rsa --私钥 id_rsa.pub --公钥 如果没有这两个文件的话就需要重新生成(有的话使用一 ...
- MySQL数据库使用xtrabackup备份实现小例子
关于MySQL数据库的备份的工具和方式也比较多,本文只简单介绍一些我司一个平台的备份方案.Xtrabackup是由percona开源的免费数据库热备份软件,但是只能对InnoDB数据库和XtraDB存 ...
- python关键字global和nonlocal总结
函数中使用全局变量 a = 100 b = 200 def func(): def sub(): return b return a + b + sub() 执行fun()后返回值为:500 a, b ...
- Elastic Search快速入门
https://blog.csdn.net/weixin_42633131/article/details/82902812 通过这个篇文章可以快速入门,快速搭建一个elastic search de ...
- 【归纳】Layui table.render里的json后台传入
在使用Layui的table元素时,传入的json的数据格式是有其自身定义的,需要另外添加一些字符,以正确传入. 为了传入符合前端格式的数据: table.render({ elem: '#test' ...
- mongodb 面试题
mongodb 面试题总结 1 nosql和关系型数据库的区别 NoSQL是非关系型数据库,NoSQL = Not Only SQL. 关系型数据库采用的结构化的数据,NoSQL采用的是键值对的方式存 ...
- mac终端方式修改host
打开终端 cd / #进入根目录 ls #查看根目录下列表,确定有需要打开的目录 cd etc #进入配置文件目录 ls sudo vim hosts #用vim打开 ...
- The main Method
The main Method You can call static methods without having any objects. For example, you never const ...
- Request Payload 和 Form Data 的区别
概述 我正在开发的项目前端和后端是完全独立的,通过配置 webpack 的 proxy 将前端请求跨域代理到后台服务.昨天发现,我前端执行 post 请求,后台 springmvc 的 @Reques ...
- Java Web学习总结(11)JDBC
一,简介 JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的 ...