mybatis一对多关联查询_字节跳动面试 Mybatis 多对一,一对多,多对多,如何写...

Mybatis之基本操作

不积跬步,无以至千里;不积小流,无以成江海。

今天我们看一下Mybatis里面的基本操作,一对多,多对一,多对多的使用。

1.一对多场景

学生和教室的关系。一个教室可以有多个学生,如何查询,老套路我们看代码.

第一步实体类

教室实体类

public class ClassRoom { private int id ; private String className; private String classAddress; private List studentList;//添加学生list属性 //get set省略}

学生实体类

public class Student { private int id; private String name; private boolean pass;//get set 省略}

第二步:接口

package com.jiepi.dao;import java.util.List;public interface ClassRoomMapper { ClassRoom findOneToMany1(int id);//嵌套结果映射:使用嵌套的结果映射来处理连接结果的重复子集 ClassRoom findOneToMany2(int id);//嵌套 Select 查询:通过执行另外一个 SQL 映射语句来加载期望的复杂类型。}

第三步:Maper映射文件(有两种实现方式)

第一种实现方式嵌套结果映射

  SELECT cr.id cr_id, className,classAddress ,name,pass from classroom cr inner join student std on cr.id=std.classroomId where cr.id=#{id} 

第二种:实现方式嵌套 Select 查询

  select id,className,classAddress from classroom where id =#{id}  select * from student where classroomId=#{classroomId} 

第三步:运行结果

 @Test public void find() { ClassRoomMapper dao = session.getMapper(ClassRoomMapper.class); ClassRoom classRoom = dao.findOneToMany1(1); System.out.println(classRoom.toString()); } @Test public void find1() { ClassRoomMapper dao = session.getMapper(ClassRoomMapper.class); ClassRoom classRoom = dao.findOneToMany2(1); System.out.println(classRoom.toString()); }

他们的运行结果是一样的

67e0bc064c10bfa7355cc4a684482e2a.png

果然返回一个教室有多个学生

2.多对一场景

多个学生只有一个教室

学生实体类

public class Student { private int id; private String name; private boolean pass; private ClassRoom classRoom; //添加房间属性//get set省略}

教室实体类

public class ClassRoom { private int id ; private String className; private String classAddress;//get set 省略}

第二步:接口

public interface StudentMapper { List findManyToOne1(); List findManyToOne2();}

第三步:配置映射文件

第一种实现方式

 SELECT name,pass,className,classAddress FROM student stu INNER JOIN classroom cr ON stu.classRoomId = cr.id 

第二种实现方式

  SELECT name,pass,classroomId FROM student   SELECT id,className,classAddress FROM classroom WHERE id = #{id} 

第四步:测试代码

 @Test public void selectList2() throws Exception { StudentMapper dao = session.getMapper(StudentMapper.class); List student = dao.findManyToOne2(); student.stream().forEach((it) -> { System.out.println(it); }); } @Test public void selectList2() throws Exception { StudentMapper dao = session.getMapper(StudentMapper.class); List student = dao.findManyToOne1(); student.stream().forEach((it) -> { System.out.println(it); }); }
8489d6057bc022c619710ce059acfb59.png

果然返回多个学生在一个教室

3.多对多场景

一个学生有多个老师,一个老师有多个学生

教师实体类

public class Teacher { private int id; private String name; private List studentList;//学生类表}

学生实体类

public class Student { private int id; private String name; private boolean pass; private List teacherList;//教师列表

教师实体和学生实体关联实体类

public class TeacherAndStudent { private Student student;//学生 private Teacher teacher;//教师}

第二步:接口

public interface TeacherAndStudentMapper { List findManyToMany();}

第三步:映射文件

  SELECT t.id teacherId,t.name teacherName,s.id studentId,s.Name studentName,s.pass studentPass from teacherAndstudent tas INNER JOIN student s ON s.id=tas.studentId INNER JOIN teacher t on t.id=tas.teacherId; 

第四步:测试结果

 @Test public void find() { TeacherAndStudentMapper dao = session.getMapper(TeacherAndStudentMapper.class); List teacherList = dao.findManyToMany(); System.out.println(teacherList.toString()); }
833cb79b6591df777dd3e2819dd987f9.png

果然返回多个老师,而每个老师有多个学生

我们把级联关系基本操作都已经演示完毕,为了让大家更加深刻,我们在再介绍一下基本的概念。

我们先解释下面的一段代码

  

关联(association)元素处理“有一个”类型的关系。比如,在我们的示例中,一个学生有一个教室。关联结果映射和其它类型的映射工作方式差不多。你需要指定目标属性名以及属性的javaType(很多时候 MyBatis 可以自己推断出来),在必要的情况下你还可以设置 JDBC 类型,如果你想覆盖获取结果值的过程,还可以设置类型处理器。关联的不同之处是,你需要告诉 MyBatis 如何加载关联。MyBatis 有两种不同的方式加载关联:

  1. 嵌套 Select 查询:通过执行另外一个 SQL 映射语句来加载期望的复杂类型。
  2. 嵌套结果映射:使用嵌套的结果映射来处理连接结果的重复子集。

两种不同的方式我们已经演示,但是在我们使用嵌套 Select 查询会存在性能问题。虽然这种方式很简单,但在大型数据集或大型数据表上表现不佳。这个问题被称为“N+1 查询问题”。概括地讲,N+1 查询问题是这样子的:

  1. 你执行了一个单独的 SQL 语句来获取结果的一个列表(就是“+1”)。
  2. 对列表返回的每条记录,你执行一个 select 查询语句来为每条记录加载详细信息(就是“N”)。

这个问题会导致成百上千的 SQL 语句被执行。有时候,我们不希望产生这样的后果。

好消息是,MyBatis 能够对这样的查询进行延迟加载(fetchType,可选的。有效值为 lazy 和 eager),因此可以将大量语句同时运行的开销分散开来(就是先执行主表信息查出来sql语句,如果需要详情信息的时候,再去执行查询详情信息sql语句,分两步执行,有些时候我们只要主表信息,不需要详情信息,就不会执行子查询了)。然而,如果你加载记录列表之后立刻就遍历列表以获取嵌套的数据,就会触发所有的延迟加载查询,性能可能会变得很糟糕。

还有一点,我们必须注意一下,先看一段代码

  //这个id元素很重要 

非常重要:id 元素在嵌套结果映射中扮演着非常重要的角色。你应该总是指定一个或多个可以唯一标识结果的属性。虽然,即使不指定这个属性,MyBatis 仍然可以工作,但是会产生严重的性能问题。只需要指定可以唯一标识结果的最少属性。显然,你可以选择主键(复合主键也可以)

集合元素(collection)和关联元素几乎是一样的,但是我们注意到一个新的 “ofType” 属性。

这个属性也是很重要的,它用来将 JavaBean(或字段)属性的类型和集合存储的类型区分开来。所以你可以按照下面这样来阅读映射

 

studentList存储着student类型的ArrayList 集合。

官网提示对关联或集合的映射,并没有深度、广度或组合上的要求。但在映射时要留意性能问题。在探索最佳实践的过程中,应用的单元测试和性能测试会是你的好帮手.

Mybatis的讲解就到这里了,如果有机会我们会对Mybatis进一步讲解,下期我们会对spring进行讲解,欢迎持续关注,抽空还会对面试题进行讲解。有什么面试题不懂的,欢迎在公众号中留言,我会依次为大家总结解答。

希望对大家面试有所帮助,也希望大家持续关注转载。关注公众号获取相关资料请回复:typescript,springcloud,springboot,nodejs,nginx,mq,javaweb,java并发实战,java并发高级进阶,实战java并发,极客时间dubbo,kafka,java面试题,ES,zookeeper,java入门到精通,区块链,java优质视频,大数据,kotlin,瞬间之美,HTML与CSS,深入体验java开发,web开发CSS系列,javaweb开发详解,springmvc,java并发编程,spring源码,python,go,redis,docker,即获取相关资料

d1e0d03bb76520ebd062ec9419042b67.png

扫码关注公主号,免费领取资料,有惊喜哟

c7045af527e2d513a2c77bcedb126ce4.png
936803a4b6b52b0c18aa820c4b33e479.png
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值