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 ...
随机推荐
- Educational Codeforces Round 69 (Rated for Div. 2) A~D Sloution
A. DIY Wooden Ladder 题意:有一些不能切的木板,每个都有一个长度,要做一个梯子,求梯子的最大台阶数 做梯子的木板分为两种,两边的两条木板和中间的若干条台阶木板 台阶数为 $k$ 的 ...
- 关于自带的sql developer修改java.exe版本的解决办法
第一次安装oracle11gR2后,就很好奇的点了一下,当点击应用程序开发下的sql developer后,就弹出一个窗口,要选择一个java.exe的路径,我就讲本机中的JDK1.7下的java.e ...
- Android生命周期例子小解
Activity 从创建到进入运行态所触发的事件 onCreate()-->onStart-->onResume() 从运行态到停止态所触发的事件 onPa ...
- smbspool - 将一个打印文件发送到一台SMB打印机
总览 SYNOPSIS smbspool {job} {user} {title} {copies} {options} [filename] 描述 DESCRIPTION 此程序是Samba(7)套 ...
- 七、WebApi跨域操作
情景:测试后返回"no response from server"? 请求响应: js调试控制台: 一.搜索安装 Microsoft.AspNet.WebApi.Cors 二.添加 ...
- css盒子模型的宽度不包括margin
看到教程上和一些博客上盒子模型的宽度 = content + padding + margin + border,应该是不包括margin的 <!DOCTYPE html> <htm ...
- 2、pycharm中设置pytest为默认运行
1.打开File-setting 2.打开Tools-Python Integrated Tools 3.找到Default test runner选项,在下拉框中选择py.test 4.点Apply ...
- bzoj2669 [cqoi2012]局部极小值 状压DP+容斥
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=2669 题解 可以发现一个 \(4\times 7\) 的矩阵中,有局部最小值的点最多有 \(2 ...
- Java二级练习试题一
为保护本地主机,对Applet安全限制中正确的是() A. Applet可加载本地库或方法 B. Applet可读.写本地计算机的文件系统 C. Applet可向Applet之外的任何主机建立网络连接 ...
- Linux进程管理工具vmstat,iostat,pmap
一查看内存的工具——vmstat (一)vmstat的介绍 vmstat vmstat是Virtual Memory Statistics(虚拟内存统计)的缩写 利用vmstat命令可以对操作系统的报 ...