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 ...
随机推荐
- Warning: session_start(): open(/var/lib/php/session/)
Warning: session_start(): open(/var/lib/php/session/) 今天放置一个新的站点www.96net.com.cn在里面,登陆后台出现这种错,之后再lin ...
- 怕忘记了CSS中position的absolute和relative用法
CSS2.0中的定位确实有时会把人弄糊涂,所以今天给它记下来,同时供以后查阅.下面写的内容有一部分借鉴了w3cschool和divcss5这两个官方网站,在此处特别的说明一下 CSS2.0中posit ...
- Spring之AOP简单demo
1.加入JAR包.出了Spring自身的Jar包还要一些依赖的JAR包.不然会报ClassNotFound. Student.java package com.lubby.bean; import o ...
- call和apply,函数伴侣
Predefined:js中的this指向直接运行上下文. call和apply是ECMASCRIPT 3在函数原型上所定义的方法,目的在于改变或指定this的指向,从而改变函数直接执行上下文.两者的 ...
- Css3-颜色 color
一.颜色 RGBA RGB是一种色彩标准,是由红(R).绿(G).蓝(B)的变化以及相互叠加来得到各式各样的颜色.RGBA是在RGB的基础上增加了控制alpha透明度的参数. 语法:color:rgb ...
- [烧脑时刻]EL表达式1分钟完事
一天,程序员A问我,我们比比谁的知识点多,反应快.我回答:那就看谁最快用EL表达式的显示在页面上吧. 话不多说,计时开始. 项目的结构如上,大概就是一个Family的JavaBean,一个jsp页面, ...
- bzoj2346 & loj2632 [Baltic 2011]Lamp 最短路
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=2346 https://loj.ac/problem/2632 题解 普及组难度的题都要想十几分 ...
- BiNGO的GO分析
GO富集分析对老师们来说想必都不陌生,几乎在任何项目中都会出现.今天就给大家介绍一款简单易学又好用的富集分析小软件---BiNGO.它是Cytoscape软件中很出色的一个插件.它提供的结果中除了文本 ...
- python 列表使用
下面实现的类似于java中的数组: names[-2]表示实现倒数的第2个参数 names[-3,-1]表示实现-3到-1的值不包含-1 增删改查 下面代码实现列表的增删改查功能: 复制copy 深c ...
- C++ 穷举算法 鸡兔同笼
#include "stdio.h" int qiongju(int head, int foot, int *chicken, int *rabbit) { int re, i, ...