学习MyBatis必知必会(8)~myBatis对象关系映射(多对一关系、一对多关系)、延迟/懒加载

简介: 学习MyBatis必知必会(8)~myBatis对象关系映射(多对一关系、一对多关系)、延迟/懒加载

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

1、多对一关系:

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


(1)myBatis发送 额外SQL:

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


20.png


//部门对象的接口、映射文件省略,跟员工逻辑差不多
/* 员工对象的接口 */
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]:

21.png


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

22.png


(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处理
目录
相关文章
|
2月前
|
SQL Java 数据库连接
MyBatis 的映射关系
MyBatis 核心功能之一是映射关系,支持一对一、一对多和多对多三种 ORM 映射。通过实体类与配置文件结合,开发者可灵活实现数据关联,提升数据库操作效率。
246 4
|
6月前
|
SQL XML Java
菜鸟之路Day35一一Mybatis之XML映射与动态SQL
本文介绍了MyBatis框架中XML映射与动态SQL的使用方法,作者通过实例详细解析了XML映射文件的配置规范,包括namespace、id和resultType的设置。文章还对比了注解与XML映射的优缺点,强调复杂SQL更适合XML方式。在动态SQL部分,重点讲解了`&lt;if&gt;`、`&lt;where&gt;`、`&lt;set&gt;`、`&lt;foreach&gt;`等标签的应用场景,如条件查询、动态更新和批量删除,并通过代码示例展示了其灵活性与实用性。最后,通过`&lt;sql&gt;`和`&lt;include&gt;`实现代码复用,优化维护效率。
551 5
|
8月前
|
SQL XML Java
七、MyBatis自定义映射resultMap
七、MyBatis自定义映射resultMap
229 6
|
9月前
|
SQL XML Java
八、(了解即可)MyBatis懒加载(或者叫延迟加载)
八、(了解即可)MyBatis懒加载(或者叫延迟加载)
272 1
|
8月前
|
Java 数据库连接 mybatis
MyBatis篇-映射关系(1-1 1-n n-n)
本文介绍了MyBatis中四种常见关系映射的配置方法,包括一对一、一对多、多对一和多对多。**一对一**通过`resultMap`实现属性与字段的映射;**一对多**以用户-角色为例,使用`&lt;collection&gt;`标签关联集合数据;**多对一**以作者-博客为例,利用`&lt;association&gt;`实现关联;**多对多**则通过引入第三方类(如UserForDept)分别在User和Dept类中添加集合属性,并配置对应的`&lt;collection&gt;`标签完成映射。这些方法解决了复杂数据关系的处理问题,提升了开发效率。
|
10月前
|
XML Java 数据库连接
Mybatis一对一,一对多关联查询
## MyBatis一对一、一对多关联查询详解 MyBatis是一款优秀的持久层框架,提供了灵活的SQL映射功能,支持复杂的数据库操作。本文将详细介绍MyBatis中一对一和一对多关联查询的实现。 ### 一对一关联查询 一对一关联关系指的是一个表中的一条记录与另一个表中的一条记录相关联。例如,一个用户有一个地址信息。 #### 数据库表设计 假设有两个表:`user`和 `address`。 ``` CREATE TABLE user ( id INT PRIMARY KEY, name VARCHAR(50) ); CREATE TABLE address
283 18
|
11月前
|
XML Java 数据库连接
Mybatis映射关系
简介:本文介绍了MyBatis框架中四种常见的关系映射方式,包括一对一、一对多、多对一及多对多。一对一通过简单属性映射实现;一对多通过在主对象中添加集合属性并使用`&lt;collection&gt;`标签映射子对象集合;多对一则利用`&lt;association&gt;`标签在主对象中映射单个子对象;多对多需引入第三方类,分别在两个主对象中添加对方的集合属性,并通过`&lt;collection&gt;`标签实现映射。
218 32
|
10月前
|
缓存 NoSQL Java
Mybatis学习:Mybatis缓存配置
MyBatis缓存配置包括一级缓存(事务级)、二级缓存(应用级)和三级缓存(如Redis,跨JVM)。一级缓存自动启用,二级缓存需在`mybatis-config.xml`中开启并配置映射文件或注解。集成Redis缓存时,需添加依赖、配置Redis参数并在映射文件中指定缓存类型。适用于查询为主的场景,减少增删改操作,适合单表操作且表间关联较少的业务。
197 6
|
SQL 缓存 Java
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
本文详细介绍了MyBatis的各种常见用法MyBatis多级缓存、逆向工程、分页插件 包括获取参数值和结果的各种情况、自定义映射resultMap、动态SQL
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
|
12月前
|
SQL Java 数据库连接
canal-starter 监听解析 storeValue 不一样,同样的sql 一个在mybatis执行 一个在数据库操作,导致解析不出正确对象
canal-starter 监听解析 storeValue 不一样,同样的sql 一个在mybatis执行 一个在数据库操作,导致解析不出正确对象