MyBatis的使用七(处理表与表之间的关系)
本文主要讲述mybatis的处理表与表之间的关系
一. 介绍t_emp和t_dept表
1. t_emp表结构
2. t_dept表结构
二. 数据表的关系
1. 阐明关系
一个部门可以有多个员工,但是一个员工只能属于一个部门
2. 实体类pojo的声明
1) Employee类的声明如下
public class Employee {
private Integer empId;
private String empName;
private Integer age;
private String gender; private Department dept; public Employee() {
} get和set()方法... @Override
public String toString() {
return "Employee{" +
"empId=" + empId +
", empName='" + empName + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
", dept=" + dept +
'}';
}
}
由于一个员工只能属于一个部门,因此在Employee中才会有 private Department dept 成员变量。
2)Department类声明如下
public class Department {
private Integer deptId;
private String deptName; private List<Employee> employees; public Department() {
} get和set()方法... @Override
public String toString() {
return "Department{" +
"deptId=" + deptId +
", deptName='" + deptName + '\'' +
", employees=" + employees +
'}';
}
}
由于一个部门可以有多个员工,因此在Department类中才会有 private List<Employee> employees 成员变量
三. 使用mybatis解决多对一【一对多】
1. 多对一的关系
这里的多对一的关系是指:多个员工在一个部门,思考的角度是站在员工Employee类的。
1)提出问题:
当需要查询单个员工信息以及所在部门时,应该如何处理?
EmpMapper接口声明如下
public interface EmpMapper {
// 根据id查询员工信息
Employee selectEmpAndDept(@Param("id") int id);
}
2)处理方式:
方式1:采用级联的方式
EmpMapper.xml文件声明如下
<!--// 根据id查询员工信息
Employee selectEmpAndDept(@Param("id") int id);-->
<!--使用: resultType="Employee"结果: Employee{empId=4, empName='赵六', age=24, gender='男', dept=null}-->
<!--级联-->
<resultMap id="resultEmpAndDept1" type="Employee">
<id column="emp_id" property="empId" />
<result column="emp_name" property="empName" />
<result column="dept_id" property="dept.deptId" />
<result column="dept_name" property="dept.deptName" />
</resultMap>
<select id="selectEmpAndDept" resultMap="resultEmpAndDept1">
SELECT t_emp.*,t_dept.`dept_name`
FROM t_emp,t_dept
WHERE t_emp.dept_id = t_dept.dept_id and emp_id = #{id}
</select>
前面提过resultMap可以自定义映射名,下面阐述<resultMap>标签
<!--
resultMap:
id:resultMap标签的唯一标识
type:返回类型
<id>:表t_emp的主键的字段名
<result>:表t_emp的非主键的字段名
其中
<result column="dept_id" property="dept.deptId" />
column:字段名dept_id,property:实体类的属性名dept.deptId
意义是将查询到的部门信息--封装--》Department对象 --赋值--》Employee类中的dept成员变量
-->
<resultMap id="resultEmpAndDept1" type="Employee">
<id column="emp_id" property="empId" />
<result column="emp_name" property="empName" />
<result column="dept_id" property="dept.deptId" />
<result column="dept_name" property="dept.deptName" />
</resultMap>
注意:<result column="dept_id" property="dept.deptId" />,是Employee类的成员对象dept . 属性名
方式2:采用 association 标签
EmpMapper.xml文件声明如下
<resultMap id="resultEmpAndDept2" type="Employee">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
<!--association的
property:是需要处理映射关系的属性名,如dept
javaType:是设置要处理属性的类型名称-->
<association property="dept" javaType="Department">
<id column="dept_id" property="deptId"></id>
<id column="dept_name" property="deptName"></id>
</association>
</resultMap>
<select id="selectEmpAndDept" resultMap="resultEmpAndDept2">
SELECT t_emp.*,t_dept.`dept_name`
FROM t_emp,t_dept
WHERE t_emp.dept_id = t_dept.dept_id and emp_id = #{id}
</select>
下面阐述<association>标签 的内容
<!--association的
property:是需要处理映射关系的属性名,如dept
javaType:是设置要处理属性的类型名称-->
<association property="dept" javaType="Department">
<id column="dept_id" property="deptId"></id>
<id column="dept_name" property="deptName"></id>
</association>
方式3:采用分步查询
先根据员工编号,查询员工信息,在根据员工信息中的部门编号,查询相对应的部门信息
因此,需要创建DeptMapper接口,DeptMapper接口的声明如下
public interface DeptMapper { // 根据id查询部门
Department selectDeptById(@Param("id") int id);
}
DeptMapper.xml文件声明如下
<!--namespace绑定mapper的接口所在的包名.接口名-->
<mapper namespace="com.hspedu.mapper.DeptMapper">
<!--// 根据id查询部门
Department selectDeptById(@Param("id") int id);-->
<select id="selectDeptById" resultType="Department">
select * from t_dept where dept_id = #{id}
</select> </mapper>
EmpMapper.xml文件声明如下
<resultMap id="resultEmpAndDept3" type="Employee">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
<!--association的
property:设置需要处理映射关系的属性的属性名
select:设置分步查询的sql语句的唯一标识
column:将select标签中查询出的某一个字段作为分步查询的条件
fetchType:是否开启延迟加载【针对某一个sql语句】eager立刻,lazy延迟
-->
<association property="dept" fetchType="eager"
select="com.hspedu.mapper.DeptMapper.selectDeptById"
column="dept_id">
</association>
</resultMap>
<select id="selectEmpAndDeptThree" resultMap="resultEmpAndDept3" >
select * from t_emp where emp_id = #{id}
</select>
下面阐述 <association> 标签的内容
<!--association的
property:设置需要处理映射关系的属性的属性名
select:设置分步查询的sql语句的唯一标识
column:将select标签中查询出的某一个字段作为分步查询的条件
fetchType:在方法中是否开启延迟加载【针对某一个sql语句】eager立刻,lazy延迟
-->
<association property="dept" fetchType="eager"
select="com.hspedu.mapper.DeptMapper.selectDeptById"
column="dept_id">
</association>
注意:association标签中的select的意义,
在t_emp表中查询到的员工信息字段中的dept_id值作为参数,传入到DeptMapper接口的selectDeptById()方法中,
在t_dept表中按照部门编号dept_id查询相对应的部门信息。
分步查询 插入一个知识点:延迟加载
a> 引入延迟加载
当我们只是想查询员工信息的姓名时,例如
@Test
// 查询指定id的员工信息
public void test02(){
Employee employee = mapper.selectEmpAndDept(4);
System.out.println(employee.getEmpName());
}
如果没有延迟加载的话,执行结果如下
DEBUG 02-04 15:37:05,646 ==> Parameters: 4(Integer) (BaseJdbcLogger.java:137)
DEBUG 02-04 15:37:05,669 ====> Preparing: select * from t_dept where dept_id = ? (BaseJdbcLogger.java:137)
DEBUG 02-04 15:37:05,669 ====> Parameters: 100(Integer) (BaseJdbcLogger.java:137)
DEBUG 02-04 15:37:05,675 <==== Total: 1 (BaseJdbcLogger.java:137)
DEBUG 02-04 15:37:05,677 <== Total: 1 (BaseJdbcLogger.java:137)
赵六
即执行了查询员工信息的sql语句,又执行了查询部门信息的sql语句,如何让它不执行查询部门信息的sql语句呢?
b> 延迟加载的配置
在mybatis-config.xml文件中添加如下setting标签,引入延迟加载
<settings>
<!--将MySQL中_映射为java的驼峰-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- 开启延时加载【懒加载】-->
<setting name="lazyLoadingEnabled" value="true"/>
<!--强制加载所有的懒配置-->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
并将<association fetchType="eager"> 的 fetchType = "lazy",即在执行该sql语句时,使用延迟加载,执行结果如下
DEBUG 02-04 15:42:26,231 ==> Preparing: select * from t_emp where emp_id = ? (BaseJdbcLogger.java:137)
DEBUG 02-04 15:42:26,261 ==> Parameters: 4(Integer) (BaseJdbcLogger.java:137)
DEBUG 02-04 15:42:26,322 <== Total: 1 (BaseJdbcLogger.java:137)
赵六
只执行了查询员工信息的sql语句,说明延迟加载有了效果。
c> 延迟加载总结:
引入延迟加载,在mybatis配置文件中添加setting标签......【全局 延迟加载】
如果对于某一个sql语句,不想使用延迟加载,则<association fetchType="eager"> 【局部 不使用延迟加载】
3)总结:
根据传入的emp_id在t_emp表中查询员工信息,员工信息的字段中包含有dept_id,然后依据dept_id,在t_dept表中查询相应的部门信息,
将部门信息--反射-->Department类的对象--赋值-->Employee类的成员变量dept。
2. 一对多关系
这里的一对多是一个部门可以有多个员工,是在Department类角度考虑的。
1)提出问题
按照部门编号查询一个部门有多少员工?
DeptMapper接口声明如下
public interface DeptMapper { // 查询一个部门有多少员工
Department selectDeptAndEmp(@Param("id") int id);
}
2)处理方式
方式1:使用collection标签
DeptMapper.xml文件声明如下
<!--// 查询一个部门有多少员工
Department selectDeptAndEmp(@Param("id") int id);-->
<resultMap id="resultDeptAndEmp1" type="Department">
<id column="dept_id" property="deptId"></id>
<result column="dept_name" property="deptName"></result>
<collection property="employees" ofType="Employee">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age" ></result>
<result column="gender" property="gender"></result>
</collection>
</resultMap>
<select id="selectDeptAndEmp" resultMap="resultDeptAndEmp1">
SELECT t_emp.*,t_dept.*
FROM t_emp,t_dept
WHERE t_emp.`dept_id` = t_dept.`dept_id` and t_dept.dept_id = #{id}
</select>
下面阐述collection标签
<collection property="employees" ofType="Employee">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age" ></result>
<result column="gender" property="gender"></result>
</collection>
property:实体类的成员变量【属性】,ofType:表示将查询的结果--封装-->实体类对象--装入-->集合
方式2:分步查询
第一步:在t_dept表中根据传入的dept_id查询部门信息
第二步:在t_emp中根据第一步中得到的dept_id查询员工信息
EmpMapper接口的声明如下
public interface EmpMapper { // 根据部门编号查询员工信息
List<Employee> selectEmployeesByDeptId(@Param("id") int id);
}
EmpMapper.xml文件声明如下
<!-- // 根据部门编号查询员工信息
List<Employee> selectEmployeesByDeptId(@Param("id") int id);-->
<resultMap id="resultEmployeesByDeptId" type="Employee">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
</resultMap>
<select id="selectEmployeesByDeptId" resultMap="resultEmployeesByDeptId">
select * from t_emp where dept_id = #{id}
</select>
DeptMapper.xml文件声明如下
<resultMap id="resultDeptAndEmp" type="Department">
<id column="dept_id" property="deptId"></id>
<result column="dept_name" property="deptName"></result>
<association property="employees" fetchType="lazy"
select="com.hspedu.mapper.EmpMapper.selectEmployeesByDeptId"
column="dept_id"></association>
</resultMap>
<select id="selectDeptAndEmpTwo" resultMap="resultDeptAndEmp">
select * from t_dept where dept_id = #{id}
</select>
使用association标签,
property:实体类需要映射处理的成员名【属性】;
select:调用EmpMapper接口的 selectEmployeesByDeptId()方法,即 根据得到的部门信息中的dept_id,在t_emp表中查询该部门的所有员工信息。
3)总结
由dept_id在t_emp查询的结果集--反射-->Employee对象--装入-->Employee集合--赋值-->Department类的employees成员变量。
MyBatis的使用七(处理表与表之间的关系)的更多相关文章
- 使用Mybatis Generator 生产 AS400中的数据表对象
第一次使用Mybatis,由于公司核心服务器是AS400,参考了网络各个大大的教程后,发现无法使用Mybatis Generator自动生成AS400中的表对象 参考URL: http://www.c ...
- MyBatis映射文件的resultMap如何做表关联
MyBatis的核心是其映射文件,SqlMap文件,里面配置了项目中用到了什么SQL语句,和数据库相关的逻辑都在这个映射文件里.顾名思义,映射文件就是对Java对象和SQL的映射.这里简单介绍一下映射 ...
- PE格式第七讲,重定位表
PE格式第七讲,重定位表 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) 一丶何为重定位(注意,不是重定位表格) 首先, ...
- MyBatis学习总结(三)——多表关联查询与动态SQL
在上一章中我们学习了<MyBatis学习总结(二)——MyBatis核心配置文件与输入输出映射>,这一章主要是介绍一对一关联查询.一对多关联查询与动态SQL等内容. 一.多表关联查询 表与 ...
- mybatis学习(五)----实现关联表查询
一.一对一的表查询 查询班级表中班级号为1的对应的记录(包括教师的具体信息) 1.首先建立数据表 数据表class和techear,class表中只有一个外键techear_id,sql脚本如下: C ...
- 菜鸟nginx源代码剖析数据结构篇(七) 哈希表 ngx_hash_t(下)
菜鸟nginx源代码剖析数据结构篇(七) 哈希表 ngx_hash_t(下) Author:Echo Chen(陈斌) Email:chenb19870707@gmail.com Blog:B ...
- 玩转SpringBoot之整合Mybatis拦截器对数据库水平分表
利用Mybatis拦截器对数据库水平分表 需求描述 当数据量比较多时,放在一个表中的时候会影响查询效率:或者数据的时效性只是当月有效的时候:这时我们就会涉及到数据库的分表操作了.当然,你也可以使用比较 ...
- MyBatis学习存档(5)——联表查询
之前的数据库操作都是基于一张表进行操作的,若一次查询涉及到多张表,那该如何进行操作呢? 首先明确联表查询的几个关系,大体可以分为一对一和一对多这两种情况,接下来对这两种情况进行分析: 一.建立表.添加 ...
- 菜鸟nginx源码剖析数据结构篇(七) 哈希表 ngx_hash_t(下)[转]
菜鸟nginx源码剖析数据结构篇(七) 哈希表 ngx_hash_t(下) Author:Echo Chen(陈斌) Email:chenb19870707@gmail.com Blog:Blog.c ...
- Spring Boot入门系列(十七)整合Mybatis,创建自定义mapper 实现多表关联查询!
之前讲了Springboot整合Mybatis,介绍了如何自动生成pojo实体类.mapper类和对应的mapper.xml 文件,并实现最基本的增删改查功能.mybatis 插件自动生成的mappe ...
随机推荐
- scrapy 如何使用代理 以及设置超时时间
使用代理 1. 单文件spider局部使用代理 entry = 'http://xxxxx:xxxxx@http-pro.abuyun.com:xxx'.format("帐号", ...
- Python基础部分:10、数据类型的内置方法和字符编码
目录 一.数据类型内置方法 1.字典dict内置方法 1.1.类型转换 2.字典必须要掌握的方法 2.1.取值方式 2.2.修改内部数据值 2.3.删除数据 2.4.统计字典中键值对个数 2.5.字典 ...
- 使用 JWT 生成 token
JWT 简介 JWT:Json Web Token 官网:https://jwt.io 优点:可生成安全性较高的 token 且可以完成时效性的检验(登陆过期检查) JWT 结构:(由官网获取) JW ...
- FluentFTP能连接却报未将对象引用设置到对象的实例。
本来项目中用的好好的FTP下载传输,不知道从什么时候开始读取不到了,也上传不了.实际读取的是本地缓存的.因为同事上传不了文件和图片才发现.上源码! #region 下载文件 static byte[] ...
- C温故补缺(十四):内存管理
内存管理 stdlib库中有几个内存管理相关的函数 序号 函数和描述 1 void *calloc(int num, int size);在内存中动态地分配 num 个长度为size 个字节 的连续空 ...
- Selenium4+Python3系列(八) - Cookie、截图、单选框及复选框处理、富文本框、日历控件操作
我所在的城市昨天出了近20+的阳性案例,但这丝毫没有 "影响" 到996的工作时间,当然,也没有影响到我想继续更新文章的决心. 一.cookie常用操作入门 上一篇有写过关于coo ...
- C++编程笔记(QT)
目录 入门基础 模态对话框 消息提示框(messagebox) 文件和目录 字体选择框 输入对话框 进度条 工具栏 控件布局 Windows托盘案例 控件 button 下拉菜单按钮 `radioBu ...
- 【Spark】Day05-内核解析:组件、流程、部署、运行模式、通讯架构、任务调度(Stage、task级)、两种Shuffle机制、内存管理、核心组件
一.内核概述 内核:核心组件的运行机制.任务调度.内存管理.运行原理 1.核心组件 (1)Driver驱动器节点:执行main方法,将程序转化为作业job,在executor中调度任务task,跟踪并 ...
- IE浏览器卸载
1.打开此电脑,点击上箭头,打开控制面板: 2.选择卸载程序: 3.点击启用或关闭Windows功能: 4.弹出Windows功能对话框,找到Inetrnet Explorer 11,取消勾选: 5. ...
- vulnhub靶场之HACKABLE: III
准备: 攻击机:虚拟机kali.本机win10. 靶机:Hackable: III,下载地址:https://download.vulnhub.com/hackable/hackable3.ova,下 ...