IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> 玩转Mybatis的高级关系映射(实战加详解,保姆级教程) -> 正文阅读

[大数据]玩转Mybatis的高级关系映射(实战加详解,保姆级教程)

目录

关联关系

一对一:在任意一方引入对方主键作为外键。
一对多:在“多”的一方,添加“一”的一方的主键作为外键。
多对多:产生中间关系表,引入两张表的主键作为外键,两个主键成为联合主键或使用新的字段作为主键。

ResultMap(结果映射)

在这里插入图片描述
简单理解如下:

<resultMap id="唯一的标识" type="映射的pojo对象">
  <id column="表的主键字段,或者可以为查询语句中的别名字段" jdbcType="字段类型" property="映射pojo对象的主键属性" />
  <result column="表的一个字段(可以为任意表的一个字段)" jdbcType="字段类型" property="映射到pojo对象的一个属性(须为type定义的pojo对象中的一个属性)"/>
  <association property="pojo的一个对象属性" javaType="pojo关联的pojo对象">
    <id column="关联pojo对象对应表的主键字段" jdbcType="字段类型" property="关联pojo对象的主席属性"/>
    <result  column="任意表的字段" jdbcType="字段类型" property="关联pojo对象的属性"/>
  </association>
  <!-- 集合中的property须为oftype定义的pojo对象的属性-->
  <collection property="pojo的集合属性" ofType="集合中的pojo对象">
    <id column="集合中pojo对象对应的表的主键字段" jdbcType="字段类型" property="集合中pojo对象的主键属性" />
    <result column="可以为任意表的字段" jdbcType="字段类型" property="集合中的pojo对象的属性" />  
  </collection>

Mybatis中javaType和jdbcType对应关系:

JDBC Type    Java Type
  
CHAR                String  
VARCHAR             String  
LONGVARCHAR         String  
NUMERIC             java.math.BigDecimal  
DECIMAL             java.math.BigDecimal  
BIT             	boolean  
BOOLEAN             boolean  
TINYINT             byte  
SMALLINT            short  
INTEGER             int  
BIGINT              long  
REAL                float  
FLOAT               double  
DOUBLE              double  

实战演练

Mybatis在映射文件中加载关联关系对象主要通过两种方式:嵌套查询和嵌套结果。下面的代码中我们将会对这两种方式进行详细的解释加运用。

相关代码

数据库相关代码

CREATE DATABASE IF NOT EXISTS resultmap DEFAULT CHARSET utf8 COLLATE utf8_general_ci;

USE resultmap

CREATE TABLE `teacher` (
  `id` INT(10) NOT NULL,
  `name` VARCHAR(30) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO teacher(`id`, `name`) VALUES (1, '秦老师'); 

CREATE TABLE `student` (
  `id` INT(10) NOT NULL,
  `name` VARCHAR(30) DEFAULT NULL,
  `tid` INT(10) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fktid` (`tid`),
  CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8


INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小明', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小红', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小张', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '1');

SELECT * FROM teacher
SELECT * FROM student

Java中的pojo老师类

package com.tz.pojo;

public class Teacher {
	private int id;
	private String name;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public String toString() {
		return "Teacher [id=" + id + ", name=" + name + "]";
	}
	
	
}

Java中的pojo学生类

package com.tz.pojo;

public class Student {
	private int id;
	private String name;
	
	//关联一个老师
	private Teacher teacher;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Teacher getTeacher() {
		return teacher;
	}

	public void setTeacher(Teacher teacher) {
		this.teacher = teacher;
	}

	@Override
	public String toString() {
		return "Student [id=" + id + ", name=" + name + ", teacher=" + teacher + "]";
	}
	
	
}

相关配置文件

  1. db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/resultmap?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
  1. mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration>
<!-- 是用 resource 属性加载外部配置文件 --> 
<properties resource="db.properties"></properties>

<typeAliases>
	<!-- <typeAlias type="com.haust.pojo.User"/> -->
	<package name="com.tz.pojo"/>
</typeAliases>




<!-- 和 spring 整合后 environments 配置将废除 -->
<environments default="development"> 
<environment id="development">
<!-- 使用 jdbc 事务管理 -->
<transactionManager type="JDBC" />
<!-- 数据库连接池 --> 
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<!-- 加载映射文件 --> 
<mappers>
	<!-- <mapper class="com.haust.mapper.UserMapper" /> -->
	<package name="com.tz.mapper"/>
</mappers>
</configuration>
  1. log4j.properties
log4j.rootCategory=INFO, stdout   
log4j.logger.com.tz=DEBUG
log4j.appender.stdout=org.apache.log4j.ConsoleAppender   
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout   
log4j.appender.stdout.layout.ConversionPattern=[QC] %p [%t] %C.%M(%L) | %m%n   

实战一:一对一

每个学生都对应一个老师,当我们查询某个学生的信息时,也能把这名学生对应老师的信息查出来
举例:(学生的tid对应老师的id,t_id为老师的id,这里为我们起的别名)
在这里插入图片描述

数据库代码如下:

SELECT student.id,student.name,student.tid,teacher.id t_id,teacher.name FROM student,teacher 
WHERE student.tid = teacher.id AND student.id = 1

方式一:嵌套结果(级联属性封装结果集)

StudentMapper.java

public Student selectStudentById(int id);

StudentMapper.xml

<mapper namespace="com.tz.mapper.StudentMapper">
	<resultMap type="com.tz.pojo.Student" id="map1">
		<id column="id" property="id" />
		<result column="name" property="name" />
		<result column="tid" property="tid"  />
		<result column="t_id" property="teacher.id" />			
		<result column="t_name" property="teacher.name"  />			
	</resultMap>
	<!--方式一  -->
	<select id="selectStudentById" resultMap="map1">
		SELECT student.id,student.name,student.tid,teacher.id t_id,teacher.name t_name FROM student,teacher 
		WHERE student.tid = teacher.id AND student.id = #{id}
	</select>

//或者
<resultMap type="com.tz.pojo.Student" id="map1">
		<id column="id" property="id" />
		<result column="name" property="name" />
		<result column="tid" property="tid"  />
		<association property="teacher" javaType="com.tz.pojo.Teacher">
			<id column="t_id" property="id" />
			<result column="t_name" property="name" />
		</association>
		<!-- <result column="t_id" property="teacher.id" />			
		<result column="t_name" property="teacher.name"  /> -->			
	</resultMap>
	<!--方式一  -->
	<select id="selectStudentById" resultMap="map1">
		SELECT student.id,student.name,student.tid,teacher.id t_id,teacher.name t_name FROM student,teacher 
		WHERE student.tid = teacher.id AND student.id = #{id}
	</select>

test.java

@Test
	public void test1() throws IOException{
		
		SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
		InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
		SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
		SqlSession sqlSession = sqlSessionFactory.openSession();
		StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
		Student student = mapper.selectStudentById(1);
		System.out.println(student);
		
		sqlSession.close();
	}

结果:

Student [id=1, name=小明, tid=1, teacher=Teacher [id=1, name=秦老师]]

结果说明:
这种方法是执行一次select查询,一次查询两个表,然后再对这个联合结果表进行映射,只有最后才是对联合结果表进行一次映射。这种方式的resultMap会自行关闭自动映射,所以需要把所有需要映射的字段都显式写出来。原因在于结果表只有一张,如果两张表中有名称相同的字段,会产生歧义。结果表可以有两个列都叫id,但是对于映射来说列名是唯一标签,所以会产生歧义。所以这种情况下,要对有歧义的列名起别名。在这种情况下association中的列名不是原列名,而是起的别名。这样得出一张结果表后,先整体映射为指定的对象类型,再把其中要映射为属性或者需要处理的列去映射成相应的属性。而把需要映射为association的列摘出来,根据提供的对象类型把它们映射成相应的对象,赋给上层的对象的属性。

方式二:嵌套查询

association分步查询

SELECT * FROM student WHERE id = 1
SELECT * FROM teacher WHERE id = 1

在这里插入图片描述
解释:
我们可以进行分步查询,即先查询出相关学生的信息,然后根据学生的tid属性(外键)查出相关老师的信息

association进行分步查询

  1. 先按照学生id查询学生信息
  2. 根据学生信息中的tid去教师表中查出学生对应的教师信息
  3. 将对应的教师相关信息设置到学生中

TeacherMapper接口:

public Teacher easySelectTeacherById(int id);

TeacherMapper.xml

<mapper namespace="com.tz.mapper.TeacherMapper">
	<select id="easySelectTeacherById" resultType="com.tz.pojo.Teacher">
		select teacher.id,teacher.name from teacher where id=#{id}
	</select>
</mapper>

StudentMapper接口:

public Student easySelectStudentById(int id);

StudentMapper.xml

<resultMap type="com.tz.pojo.Student" id="map">
		<id column="t_id" property="id"/>
		<result column="t_name" property="name"/>
		<result column="tid" property="tid"/>
		<!-- 
			association定义关联对象的封装规则
			property:当前resultMap type的pojo对象所关联的属性(在本例中是teacher对象)
			select:表面当前属性是调用select指定的方法查出的结果
			column:指定将哪一列的值传给这个select语句
		 -->
		<association property="teacher"
		javaType="com.tz.pojo.Teacher" 
		select="com.tz.mapper.TeacherMapper.easySelectTeacherById" 
		column="tid">
			
		</association>
	</resultMap>
	<!--方式二  -->
	<select id="easySelectStudentById" resultMap="map">
		SELECT id t_id,name t_name,tid FROM student WHERE id = #{id}
	</select>

测试:

@Test
	public void test2() throws IOException{
		
		SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
		InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
		SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
		SqlSession sqlSession = sqlSessionFactory.openSession();
		StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
		Student student = mapper.easySelectStudentById(2);
		System.out.println(student);
		sqlSession.close();
	}

代码说明:
association中嵌套select语句,这样的执行顺序是:先执行上层select找出resultMap中除了复杂映射的其他部分,默认开启部分自动映射,因此其他部分会被自动映射,除了有的映射不到,需要使用类型处理器。接着执行association中的select语句,并且将column值(如果列起的别名需要将别名传入)作为参数传入easySelectTeacherById,tid就会被当做easySelectTeacherById中的 #{id} ,执行完之后将查询结果进行封装然后 自动映射到assiciation中,因为在TeacherMapper.xml中已经将teacher对象封装好并将相关值进行传递,所以在StudentMapper.xml文件中的resultmap中的association属性中不需要再添加子属性进行显示的映射

结果:
在这里插入图片描述
在这里插入图片描述
过程说明:

使用association定义关联的单个对象的封装规则
我们查询的主体是学生,然后需要把一些额外的信息加上(学生对应的老师的相关信息)

这样做相当于把查询分了两步:
1.在Student中先select查询id为给定值的所有元组(行),把能自动映射或者指定了类型处理器的属性先映射到Student对象上

2.再根据上述元组中的tid属性去select查询Teacher表中id值等于Student中tid的行,并把查询结果集映射到Teacher对象上,并且把这个Teacher对象赋给上面的Student对象的teacher属性

整体就是两步select,根据第一步查询出的结果的某个字段去进行第二步查询。
先构建出第一步查询的结果对象obj1,然后把第二步查询的结果对象obj2赋给obj1对应的属性。

(先得到结果表1,对其进行映射,再使用其中的某字段得到结果表2,再对结果表2进行映射,将映射结果2嵌入映射结果1的属性中。整个过程产生了两张结果表,因为有两个select,因为是先后查询两张表,所以表中有重复的字段也不会产生冲突)

实战一总结

1.如果使用了select属性,则本质上要进行两次查询,得到两张结果表,因为是从不同的表中查询(相同也无所谓)且每次只查询一个表,所以二者互不干涉,所以不存在字段歧义的问题,自动映射会开启。对于分步查询(涉及到association属性),则传给select需要赋值的列的属性不会自动映射,其余属性会自动映射(在满足自动映射的条件下),分步查询依次查询两张表,即使两张表中有相同的字段名也不会冲突
2.如果使用resultMap属性,或者association本身当做一个resultMap(嵌套结果),则本质是对多张表的一次联合查询,只产生一张结果表。然后对这张结果表一次进行映射。可能存在字段歧义问题,自动映射会关闭(如果没有指明映射关系的字段会得到空值)。此时要把产生歧义的字段起别名,并且把所有需要映射的字段都显式写出来。

分步查询扩展说明

对于多个表中均出现属性名与字段名不匹配的问题
以上面的例子为例:
student属性如下:

	private int id;
	private String name;
	private int tid;
	private Teacher teacher;

我们在查询时起个别名

SELECT id sid,name sname,tid stid FROM student WHERE id = #{id}
//上面之所以是where id 而不是 where sid 与数据库的执行顺序有关

这时需要
用resultmap对其进行映射

<resultMap type="com.tz.pojo.Student" id="map">
		<id column="sid" property="id"/>
		<result column="sname" property="name"/>
		<result column="stid" property="tid"/>
		<association property="teacher"
		javaType="com.tz.pojo.Teacher" 
		select="com.tz.mapper.TeacherMapper.easySelectTeacherById" 
		column="stid">
			
		</association>
	</resultMap>

teacher属性如下:

	private Integer id;
	private String name;

字段名如下:

t_id
t_name

方法一:起别名,在查询时将字段名的别名与属性名变为一致(这样使用resultType即可)

select t_id id,t_name name from teacher where t_id=#{tid}

方法二:resultMap

<resultMap type="com.tz.pojo.Teacher" id="teacherMap">
		<id column="t_id" property="id"/>
		<result column="t_name" property="name"/>
	</resultMap>
	<select id="easySelectTeacherById" resultMap="teacherMap">
		select t_id,t_name from teacher where t_id=#{tid}
	</select>

总结:
对于分步查询
在这里插入图片描述
第一步:先执行
在这里插入图片描述
然后查出来相关内容到resultmap上进行映射
在这里插入图片描述

然后执行association里面的select语句,将查询结果映射到其resultmap中(类名与字段名不一致的情况下)
在这里插入图片描述
然后将封装好的Teacher对象赋值给student的属性teacher。
在这里插入图片描述
第一个resultMap的association属性中无需再用子属性进行显示的封装,因为在执行完association属性中的select对应的sql语句之后,已经进行了封装,封装好后直接传递给association(javaType和property等属性已经可以确保正确接收),此时也不存在字段名和属性名不一致的映射问题,字段名和属性名不一致的映射问题在执行association属性中的select对应的sql语句之后进行相关值的封装时应该进行解决。
对照本例:
此时在封装teacher对象时进行字段名和属性名不一致问题的解决(如果不一致时)
在这里插入图片描述
然后将封装好的Teacher对象(此时已经解决了字段名和属性名不一致的问题了,所以association属性无需再设置相关子属性进行映射,此时已经开启自动映射)赋值给association属性即可

嵌套查询(分步查询)的延迟加载

在mybatis-config.xml文件的<settings>中进行配置
在这里插入图片描述

一对多

场景:
一个老师教很多个学生,我们在查询某个老师(主体)的信息时需要将相关学生的信息查询出来
例如:

SELECT teacher.`t_id`,teacher.`t_name`,student.`id`,student.`name`,student.`tid` FROM teacher,student
WHERE teacher.`t_id`=student.`tid` 

结果:
在这里插入图片描述

嵌套结果

此时需要在Teacher.java中添加下面代码

	private List<Student> students;
	public List<Student> getStudents() {
			return students;
		}
	public void setStudents(List<Student> students) {
			this.students = students;
		}

TeacherMapper.java

public Teacher selectTeacherAndStudent(int id);

TeacherMapper.xml

<resultMap type="com.tz.pojo.Teacher" id="teacherAndStudent">
		<id column="t_id" property="id"/>
		<result column="t_name" property="name"/>
		<!-- collection定义关联集合类型的属性的封装规则 
			ofType:指定集合里面元素的类型
		-->
		<collection property="students" ofType="com.tz.pojo.Student">
			<id column="id" property="id"/>
			<result column="name" property="name"/>
			<result column="tid" property="tid"/>
			<association property="teacher" javaType="com.tz.pojo.Teacher">
				<id column="t_id" property="id"/>
				<result column="t_name" property="name"/>
			</association>
		</collection>
			
	</resultMap>
	<!-- 一对多方式一嵌套结果 -->
	<select id="selectTeacherAndStudent" resultMap="teacherAndStudent">
		SELECT teacher.`t_id`,teacher.`t_name`,student.`id`,student.`name`,student.`tid` FROM teacher,student
			WHERE teacher.`t_id`=student.`tid` AND teacher.`t_id`=#{id}
	</select>

测试代码

@Test
	public void test4() throws IOException{
		
		SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
		InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
		SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
		SqlSession sqlSession = sqlSessionFactory.openSession();
		TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
		Teacher t = mapper.selectTeacherAndStudent(1);
		
		System.out.println(t);
		sqlSession.close();
	}

结果:
在这里插入图片描述
在这里插入图片描述

方法二嵌套查询

思路与相关注意事项与一对一查询类似,这里就不再赘述

SELECT * FROM teacher WHERE t_id = 1
SELECT * FROM student WHERE tid = 1

为方便演示,在Student.java中暂时将teacher属性打上注释

StudentMapper.java

public List<Student> selectStudentsByTid(int tid);

StudentMapper.xml

<select id="selectStudentsByTid" resultType="com.tz.pojo.Student">
		select * from student where tid = #{tid}
	</select>

TeacherMapper.java

public Teacher selectTeacherById(int id);

TeacherMapper.xml

<resultMap type="com.tz.pojo.Teacher" id="teacherAndStudent2">
		<id column="t_id" property="id"/>
		<result column="t_name" property="name"/>
		<!-- collection定义关联集合类型的属性的封装规则 
			ofType:指定集合里面元素的类型
		-->
		<collection property="students" ofType="com.tz.pojo.Student"
		select="com.tz.mapper.StudentMapper.selectStudentsByTid" column="t_id">
			<id column="id" property="id"/>
			<result column="name" property="name"/>
			<result column="tid" property="tid"/>
			<association property="teacher" javaType="com.tz.pojo.Teacher">
				<id column="t_id" property="id"/>
				<result column="t_name" property="name"/>
			</association>
		</collection>
	</resultMap>
	<!-- 一对多方式二嵌套查询 -->
	<select id="selectTeacherById" resultMap="teacherAndStudent2">
		select * from teacher where t_id = #{id}
	</select>

测试代码

@Test
	public void test5() throws IOException{
		
		SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
		InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
		SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
		SqlSession sqlSession = sqlSessionFactory.openSession();
		TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
		Teacher t = mapper.selectTeacherById(1);
		
		System.out.println(t);
		sqlSession.close();
	}

结果
在这里插入图片描述
在这里插入图片描述

多对一

多个学生对应一个老师,当我们一次性查多个学生时,可以将其对应的老师相关信息也查出来

例如:

SELECT student.`id`,student.`name`,student.`tid`,teacher.`t_id`,teacher.`t_name` FROM student,teacher
WHERE student.`tid` = teacher.`t_id`

在这里插入图片描述
为了更好地演示,我们将数据库表进行了一些修改如上图所示,然后对pojo表的更新如下:
Student.java

private int id;
	private String name;
	private int tid;
	private Teacher teacher;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getTid() {
		return tid;
	}
	public void setTid(int tid) {
		this.tid = tid;
	}
	public Teacher getTeacher() {
		return teacher;
	}
	public void setTeacher(Teacher teacher) {
		this.teacher = teacher;
	}
	@Override
	public String toString() {
		return "Student [id=" + id + ", name=" + name + ", tid=" + tid + ", teacher=" + teacher + "]";
	}

Teacher.java

private Integer id;
	private String name;
	
	public Integer getId() {
		return id;
	}


	public void setId(Integer id) {
		this.id = id;
	}


	public String getName() {
		return name;
	}


	public void setName(String name) {
		this.name = name;
	}


	@Override
	public String toString() {
		return "Teacher [id=" + id + ", name=" + name + "]";
	}

方法一:嵌套结果

StudentMapper.java

public List<Student> selectStudentsALL();

StudentMapper.xml

<resultMap type="com.tz.pojo.Student" id="allStudent">
		<id column="id" property="id"/>
		<result column="name" property="name"/>
		<result column="tid" property="tid"/>
		<association property="teacher" javaType="com.tz.pojo.Teacher">
			<id column="t_id" property="id" />
			<result column="t_name" property="name" />
		</association>
	</resultMap>
	<!--多对一  -->
	<select id="selectStudentsALL" resultMap="allStudent">
	SELECT student.`id`,student.`name`,student.`tid`,teacher.`t_id`,teacher.`t_name` FROM student,teacher
	WHERE student.`tid` = teacher.`t_id`
	</select>

测试代码

@Test
	public void test6() throws IOException{
		
		SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
		InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
		SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
		SqlSession sqlSession = sqlSessionFactory.openSession();
		StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
		List<Student> list = mapper.selectStudentsALL();
		
		System.out.println(list);
		sqlSession.close();
	}

结果
在这里插入图片描述
在这里插入图片描述

方法二嵌套查询

TeacherMapper.java

public Teacher selectTeacherById2(int id);

TeacherMapper.xml

<resultMap type="com.tz.pojo.Teacher" id="map6">
		<id column="t_id" property="id"/>
		<result column="t_name" property="name"/>
	</resultMap>
	<select id="selectTeacherById2" resultMap="map6">
		select * from teacher where t_id = #{id}
	</select>

StudentMapper.java

public List<Student> selectStudentsALL2();

StudentMapper.xml

<resultMap type="com.tz.pojo.Student" id="allStudent2">
		<id column="id" property="id" />
		<result column="name" property="name" />
		<result column="tid" property="tid"  />
		<association property="teacher" javaType="com.tz.pojo.Teacher"
		select="com.tz.mapper.TeacherMapper.easySelectTeacherById" column="tid">
			
		</association>	
	</resultMap>
	<!--多对一嵌套查询  -->
	<select id="selectStudentsALL2" resultMap="allStudent2">
		select * from student
	</select>

测试代码

@Test
	public void test7() throws IOException{
		
		SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
		InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
		SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
		SqlSession sqlSession = sqlSessionFactory.openSession();
		StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
		List<Student> list = mapper.selectStudentsALL2();
		
		System.out.println(list);
		sqlSession.close();
	}

结果:
在这里插入图片描述
在这里插入图片描述
根据日志的理解:
先查询出了所有学生(此时只有学生的一些字段),然后开始查询第一个学生的tid(2),将其作为参数传递给select中的sql语句,然后查出来id为2的老师,然后将id为2的老师的相关信息映射到所有tid为2的学生信息中。此时tid为1的学生的老师相关信息还没有,然后将tid(1)将其作为参数传递给select中的sql语句,然后查出来id为1的老师,然后将id为1的老师的相关信息映射到所有tid为1的学生信息中。

扩展:嵌套查询传递多列值及延迟加载

在这里插入图片描述

总结

  1. 在使用resultmap的情况下,不涉及多表查询,仅仅是单表查询,会自动映射,在resultmap的子元素中只需要处理字段名和属性名不一致的情况即可。
  2. 多表查询时,如果是嵌套结果则会关闭自动映射,因为仅仅select一次,产生一张表,如果开启自动映射时可能会产生字段名相同的冲突,所以需要显示的写出相关的映射代码。
  3. 多表查询时,如果是嵌套查询则会开启自动映射,若为两张表时,通过观察日志记录可知,会产生两张表,但是一张表可能会查询多次(在多对一的情况下)。
  4. 对于association中的select值为:名称空间.id。
  5. 在多表的嵌套查询时,resultMap的association属性不用再写子属性进行映射,因为association中的select的sql语句执行完之后将相关对象封装好赋值给association,此时已经没有字段名和属性名不一致的问题且已经开启了自动映射。
  6. resultMap的type属性是查询的pojo主体(以谁为主),且此pojo主体中有与之相关连(主体的附加信息,比如查询学生(主体),需要将相关老师(与主体相关联)的信息也查出来)的pojo属性。
  7. 从一对多或者多对一运行的日志记录来看,嵌套查询的第一个select语句在查询出主体pojo的多条记录(此时只有主体pojo的属性值,关联pojo的相关信息需要下一个select(子查询)获取),若tid为association属性中select的参数,此时需要根据第一行记录的tid(假设为1)作为参数传递给association属性中select的sql语句,查询完毕后封装对象,赋值给所有tid为1的主体,若此时还有tid为2的记录(行),则重复上述操作,直至不同tid值的记录的所需要查询的值(关联pojo的相关信息)全部查询完毕。
  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2021-11-09 19:37:21  更:2021-11-09 19:37:28 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 5:49:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码