一、myBatis对象关系映射(多对一关系、一对多关系)

1、多对一关系:

---例子:多个员工同属于一个部门。


(1)myBatis发送 额外SQL:

■ 案例:员工表通过 dept_id 关联 部门表,需求:查询指定员工id、name、所属的部门名称的信息。

//部门对象的接口、映射文件省略,跟员工逻辑差不多

/* 员工对象的接口 */
public interface EmployeeMapper {
Employee get(Long id);
} <!--员工对象的映射文件-->
<!-- 解决列名和属性名不匹配问题 -->
<resultMap id="BaseResultMap" type="Employee">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="dept_id" property="dept.id"/>
</resultMap> <!-- 查询操作 -->
<select id="get" resultMap="BaseResultMap">
select id, name, dept_id from employee2 where id = #{id}
</select> /* 测试:查询指定员工id、name、所属的部门名称的信息 */
@Test
public void testGet() throws Exception {
SqlSession session = MyBatisUtil.getSession();
EmployeeMapper employeeMapper = session.getMapper(EmployeeMapper.class);
Employee e = employeeMapper.get(1L);
System.out.println(e);
//需要通过查询得到的dept_id查询获取得到部门对象
/**
* 额外的查询语句,可以通过配置resultMap的association属性,让myBatis帮我们执行
*/
//手动添加额外查询语句
// Long dept_id = e.getDept().getId();
// DepartmentMapper departmentMapper = session.getMapper(DepartmentMapper.class);
// Department d = departmentMapper.get(dept_id);
// e.setDept(d); System.out.println(e.getDept());
session.commit();
session.close();
}
  • 上面是通过手动添加的额外SQL查询,通过配置resultMap的association属性,让myBatis帮我们执行如下:

	<!-- 解决列名和属性名不匹配问题 -->
<resultMap id="BaseResultMap" type="Employee">
<id column="id" property="id"/>
<result column="name" property="name"/>
<!--<result column="dept_id" property="dept.id"/> -->
<!-- 额外的SQL配置方式
association元素:配置单一元素的关联关系
property 属性:对象的属性
select 属性:发送额外的sql
column 属性: 将指定的列的值传递给额外sql
-->
<association property="dept"
select="com.shan.hello.mappe r.DepartmentMapper.get"
column="dept_id"
/> </resultMap>

(2)使用额外的 SQL 做映射配置会导致的问题:N+1问题

例如:每个员工的部门编号dept_id 是不同的,当查询所有员工的id、name、所属的部门名称的信息时就会发送额外N条SQL语句。

  • N:发送额外N条SQL语句去查询员工所属的部门名称: select name from department where id = dept_id;

  • 1:查询所有员工的id、name、所属的部门的编号dept_id:select * from employee;

----解决:使用内联映射(多表查询),此时一条 SQL 语句搞定。

----处理多表查询的结果集的方法:内联映射

(3)对象关联的查询:

方式一:额外的SQL

方式二:内联映射

(4)处理多表查询的结果集的方法【内联映射】:

  • 方式一:属性名-列名 通过resultMap的子元素result进行映射配置[内联映射-使用result]:

  • 方式二:属性名-列名 通过resultMap的子元素association进行映射配置[内联映射-使用association]

(5)多对一关系配置总结:

使用association元素,配置单一对象属性。

  • 方式一:额外的SQL[分步查询],一般需要进入另外一个页面展示更加详细的信息。
  • 方式二:内联映射[多表查询],常用。需要在列表中显示关联对象的数据,使用内联映射,否则会出现N+1问题。

2、一对多关系配置:

---例子:一个部门有多个员工。


(1)一对多关系-额外的SQL:

<!-- 针对单一对象的属性,使用association元素 -->
<!-- 针对集合类型的属性,使用collection元素 -->
<!-- 额外的SQL配置方式
collection元素:配置集合类型元素的关联关系
property 属性:对象的属性
select 属性:发送额外的sql
column 属性: 将指定的列的值传递给额外sql
--> <resultMap id="BaseResultMap" type="Department">
<id column="id" property="id"/>
<result column="name" property="name"/>
<!--<result column="" property="emps"/> -->
<collection property="emps"
select="com.shan.hello.mapper.EmployeeMapper.get"
column="id" >
</collection>
</resultMap> <select id="get" resultMap="BaseResultMap">
select id, name from department where id = #{id}
</select>

(2)一对多关系-内联查询:

<!-- 针对单一对象的属性,使用association元素 -->
<!-- 针对集合类型的属性,使用collection元素 -->
<resultMap id="BaseResultMap" type="Department">
<id column="id" property="id"/>
<result column="name" property="name"/>
<!--<result column="" property="emps"/> -->
<!--
内联查询:ofType是集合中泛型的类型
-->
<collection property="emps" ofType="Employee">
<result column="e_id" property="id"/>
<result column="e_name" property="name"/>
<result column="e_dept_id" property="deptId"/>
</collection>
</resultMap> <select id="get" resultMap="BaseResultMap">
<!-- select id, name from department where id = #{id} -->
select d.id, d.name, e.id e_id, e.name e_name, e.dept_id e_dept_id from department d
join employee2 e on d.id = e.dept_id where d.id = #{id}
</select>

二、设置延迟/懒加载

  	<!-- 全局配置文件 -->
<settings>
<!-- 懒加载/延迟加载,开启延迟加载功能 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 设置不要积极地去查询关联对象 -->
<setting name="aggressiveLazyLoading" value="false"/>
<!-- 延迟加载的触发方法 -->
<setting name="lazyLoadTriggerMethods" value="close"/>
</settings>
  • 动态代理-增强功能--延迟加载

总结:多对一、一对多关系的单属性对象/集合属性对象,使用association或collection元素?使用额外SQL或内联查询?

  • 针对【单属性对象】:使用assoication元素,通常需要使用多表查询操作,即内联查询

  • 针对【集合属性对象】:使用collection元素,通常还要使用延迟加载,即额外SQL处理

MyBatis加强(1)~myBatis对象关系映射(多对一关系、一对多关系)、延迟/懒加载的更多相关文章

  1. 019 关联映射文件中集合标签中的lazy(懒加载)属性

    <set>.<list>集合上,可以取值:true/false/extra,(默认值为:true) 实例一:(集合上的lazy=true(默认))class默认lazy=tru ...

  2. 018 关联映射文件中<class>标签中的lazy(懒加载)属性

    Lazy(懒加载): 只有在正真使用该对象时,才会创建这个对象 Hibernate中的lazy(懒加载): 只有我们在正真使用时,它才会发出SQL语句,给我们去查询,如果不使用对象则不会发SQL语句进 ...

  3. hibernate学习五(关系映射多对一与一对多)

    一.多对一 多对一(或者一对多):在学生与老师的情况下,一个老师可以教多个学生,但一个学生只能被教一个老师教: 对于类:在多的那方拥有一的那方的一个实体 二.修改student.java和teache ...

  4. mybatis(三)懒加载

    懒加载的好处: 所谓懒加载(lazy)就是延时加载,延迟加载.什么时候用懒加载呢,我只能回答要用懒加载的时候就用懒加载.至于为什么要用懒加载呢,就是当我们要访问的数据量过大时,明显用缓存不太合适,因为 ...

  5. 关于 Mybatis 设置懒加载无效的问题

    看了 mybatis 的教程,讲到关于mybatis 的懒加载的设置: 只需要在 mybatis 的配置文件中设置两个属性就可以了: <settings> <!-- 打开延迟加载的开 ...

  6. MyBatis --- 映射关系【一对一、一对多、多对多】,懒加载机制

    映射(多.一)对一的关联关系 1)若只想得到关联对象的id属性,不用关联数据表 2)若希望得到关联对象的其他属性,要关联其数据表 举例: 员工与部门的映射关系为:多对一 1.创建表 员工表 确定其外键 ...

  7. Mybatis学习(四)————— 高级映射,一对一,一对多,多对多映射

    一.单向和双向 包括一对一,一对多,多对多这三种情况,但是每一种又分为单向和双向,在hibernate中我们就详细解析过这单向和双向是啥意思,在这里,在重复一遍,就拿一对多这种关系来讲,比如有员工和部 ...

  8. Spring Data JPA 关系映射(一对一,一对多,多对多 )

    CascadeType.REMOVE 级联删除操作,删除当前实体时,与它有映射关系的实体也会跟着被删除.CascadeType.MERGE 级联更新(合并)操作,当Student中的数据改变,会相应地 ...

  9. mybatis 详解(八)------ 懒加载

    本章我们讲如何通过懒加载来提高mybatis的查询效率. 本章所有代码:http://pan.baidu.com/s/1o8p2Drs 密码:trd6 1.需求:查询订单信息,有时候需要关联查出用户信 ...

随机推荐

  1. TKE 用户故事 - 作业帮 PB 级低成本日志检索服务

    作者 吕亚霖,2019年加入作业帮,作业帮架构研发负责人,在作业帮期间主导了云原生架构演进.推动实施容器化改造.服务治理.GO微服务框架.DevOps的落地实践. 莫仁鹏,2020年加入作业帮,作业帮 ...

  2. Pydantic使用

    Pydantic可以在代码运行时提供类型提示, 数据校验失败时提供友好的错误提示, 使用Python的类型注解来进行数据校验和settings管理 一般使用 from datetime import ...

  3. Java高效开发-fiddler抓包工具

    1.简介 Fiddler是最常用的抓包工具之一,只要打开之后就能够实现数据包抓取,关闭之后会自动取消代理,非常方便本地调试 2.下载 阿里云盘地址:https://www.aliyundrive.co ...

  4. 三角网格上的寻路算法Part.2—A*算法

    背景 继上一篇三角网格Dijkstra寻路算法之后,本篇将继续介绍一种更加智能,更具效率的寻路算法-A*算法,本文将首先介绍该算法的思想原理,再通过对比来说明二者之间的相同与不同之处,然后采用类似Di ...

  5. Java--Map的使用认知

    Java里面的Map是一个抽象接口,有一些类实现的该接口比如HashMap.TreeMap等 HashMap 是一个散列表,存储的内容是靠键值对来映射的(key-value). 基本认识 HashMa ...

  6. js箭头函数 的 (e) => { } 写法笔记

    1. (e) => {} 是ES 6 新语法,默认是Es 5.1,因此在这里设置一下就不会提示红色下划线了 2.使用: (e) => {}  , 其实就是function (e){} 的缩 ...

  7. 注意,你所做的 A/B 实验,可能是错的!

    对于 A/B 实验原理认知的缺失,致使许多企业在业务增长的道路上始终在操作一批"错误的 A/B 实验".这些实验并不能指导产品的优化和迭代,甚至有可能与我们的初衷背道而驰,导致&q ...

  8. 《剑指offer》面试题68 - II. 二叉树的最近公共祖先

    问题描述 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先. 百度百科中最近公共祖先的定义为:"对于有根树 T 的两个结点 p.q,最近公共祖先表示为一个结点 x,满足 x 是 p.q ...

  9. 1000粉!使用Three.js制作一个专属3D奖牌🥇

    背景 破防了 !突然发现 SegmentFault 平台的粉丝数量已经突破 1000 了,它是我的三个博客平台掘金.博客园.SegmentFault中首个粉丝突破 1000 的,于是设计开发这个页面, ...

  10. c#操作符详解

    操作符概览 操作符(Operator)也译为"运算符" 操作符是用来操作数据的,被操作符操作的数据称为操作数(Operand) 操作符的本质 操作符的本质是函数(即算法)的&quo ...