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 ...
随机推荐
- 抓包分析 TCP 握手和挥手
前言 首先需要明确的是 TCP 是一个可靠传输协议,它的所有特点最终都是为了这个可靠传输服务.在网上看到过很多文章讲 TCP 连接的三次握手和断开连接的四次挥手,但是都太过于理论,看完感觉总是似懂非懂 ...
- springboot集成支付宝的支付(easy版)
SpringBoot对接支付宝 需要先注册账号 到支付宝开发者平台创建网页支付应用 启用公钥模式 需要使用到appId和下面的两个秘钥 写配置信息的代码 1.引入依赖 <dependency&g ...
- 题解合集 (update on 11.5)
收录已发布的题解 按发布时间排序. 部分可能与我的其他文章有重复捏 qwq . AtCoder for Chinese: Link ZHOJ: Link 洛谷 \(1\sim 5\) : [题解]CF ...
- mybatis实现数据行级权限拦截
最近在做一个测试平台,其中有一个需求是用户只能看到他有权限的项目数据.一开始这个需求只针对用例模块,我直接在sql后面加上了关联项目权限表.后面因为其他模块也需要这个权限判断,故打算把关联sql抽取出 ...
- PGL图学习之图神经网络GraphSAGE、GIN图采样算法[系列七]
0. PGL图学习之图神经网络GraphSAGE.GIN图采样算法[系列七] 本项目链接:https://aistudio.baidu.com/aistudio/projectdetail/50619 ...
- netty系列之:在netty中使用proxy protocol
目录 简介 netty对proxy protocol协议的支持 HAProxyMessage的编码解码器 netty中proxy protocol的代码示例 总结 简介 我们知道proxy proto ...
- python进阶(28)import导入机制原理
前言 在Python中,一个.py文件代表一个Module.在Module中可以是任何的符合Python文件格式的Python脚本.了解Module导入机制大有用处. 1. Module组成 一个.p ...
- 关于led蓝牙控制器ble通信分析
前言 前几天在网上买了一个led蓝牙控制器,可以用手机app通过蓝牙连接控制rgb led灯,当然这个也是属于ble通信.之前我写过一篇体重称蓝牙通信的,不过那个较为简单,数据也是靠分析出来的. 这次 ...
- 关于linux mint更改资源管理器的快捷键
前言 首先要知道 linux mint 的默认资源管理器是 nemo 我很不习惯 ctrl+d 在nemo里面是 收藏到侧边栏 我习惯 ctrl+d 在windows上是删除文件 所以下面我就修改这个 ...
- 07#Web 实战:实现 GitHub 个人主页项目拖拽排序
实现效果图 GitHub 和 Gitee 个人主页中可以对自己的项目进行拖拽排序,于是我就想自己实现一个.本随笔只是记录一下大概的实现思路,如果感兴趣的小伙伴可以通过代码和本随笔的说明去理解实现过程. ...