昔洛 的个人博客

Bug不空,誓不成佛

  menu
70 文章
14633 浏览
4 当前访客
ღゝ◡╹)ノ❤️

第九篇 MyBatis 的关联映射

一、关联关系概述

    在关系型数据库中,多表之间存在着三种关联关系,分别是一对一、一对多和多对多。
这三种关联关系的具体说明如下:

  • 一对一:在任意一方引入对方主键作为外键。

  • 一对多:在“多”的一方,添加“一”的一方的主键作为外键。

  • 多对多:产生中间关系表,引入两张表的主键作为外键,两个主键成为联合主键或使用新的字段作为主键。
    通过数据库中的表可以描述数据之间的关系,同样,在 Java 中,通过对象也可以进行关系描述,如下图所示:
    image.png
    上图中,三种关联关系的描述如下:

  • 一对一的关系:就是在本类中定义对方类型的对象,如 A 类中定义 B 类类型的属性 b,B 类中定义 A 类类型的属性 a。

  • 一对多的关系:就是一个 A 类类型对应多个 B 类类型的情况,需要在 A 类中以集合的方式引入 B 类类型的对象,在 B 类中定义 A 类类型的属性 a。

  • 多对多的关系:在 A 类中定义 B 类类型的集合,在 B 类中定义 A 类类型的集合。

二、一对一

    MyBatis 中利用元素<association>来处理一对一关联,在<association>元素中,通常可以配置一下属性。

  • property:指定映射到的实体类对象属性,与表字段一一对应。
  • column:指定表中对应的字段。
  • javaType:指定映射到实体对象属性的类型。
  • select:指定引入嵌套查询的子 SQL 语句,该属性用于关联映射中的嵌套查询。
  • fetchType:指定在关联查询时是否启用延迟加载。fetchType 属性有 lazy 和 eager 两个属性值,默认值为 lazy(即默认关联映射延迟加载)

<association>元素的使用非常简单,只需要参考如下两种示例配置即可,具体如下:

<!-- 方式一:嵌套查询 -->
<association property="card" column="card_id"
		   javaType="com.cn.po.IdCard"
		   select="com.cn.mapper.IdCardMapper.findCodeByid" />
<!-- 方式二:嵌套结果 -->
<association property="card" javaType="com.cn.po.IdCard">
	<id property="id" column="card_id" />
	<result property="code" column="code" />
</association>	

提示:MyBatis 在映射文件中加载关联对象主要通过两种方式:嵌套查询和嵌套结果。嵌套查询是通过执行另外一条 SQL 映射语句来返回预期的复杂类型;嵌套结果是使用嵌套结果映射来处理重复的联合结果的子集。开发人员可以使用上述任一一种方式实现对关联关系的加载。

查询个人及其关联的身份证信息是先通过查询个人表中的主键来获取个人信息,然后通过表中的外键,来获取证件中表中的身份证号信息。具体实现步骤如下:
(1)创建数据表。在 mybatis 数据库中分别创建名为 tb_idcard 和 tb_person 的数据表,同时预先插入两条数据。其执行的 SQL 语句如下:

use mybatis;
# 创建一个名称为 tb_idcard 的表
create table tb_idcard(
	id int primary key auto_increment,
	code varchar(18)
);
# 插入两条数据
insert into tb_idcard(code) values('152221198711020624');
insert into tb_idcard(code) values('152201199008150317');
#创建一个名称为 tb_person 的表
create table tb_person(
	id int primary key auto_increment,
	name varchar(32),
	age int,
	sex varchar(8),
	card_id int unique,
	foreign key(card_id) references tb_idcard(id)
);
# 插入两条数据
insert into tb_person(name,age,sex,card_id) values('Rose','29','女',1);
insert into tb_person(name,age,sex,card_id) values('Tom','27','男',2);

完成上述操作后,数据库 tb_idcard 和 tb_person 表中的数据如下:
image.png
(2)在 Eclipse 中创建一个新的项目,然后引入相关 JAR 包、log4j 日志文件、MybatisUtils 工具类以及 mybatis-config.xml 核心配置文件。目录结构如图所示:
image.png
(3)在项目的 com.cn.po 包下创建持久化类 IdCard 和 Person,代码如下:
idCard.java

package com.cn.po;
/*
 * 证件持久化类
 */
public class IdCard {
	private Integer id;
	private String code;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getCode() {
		return code;
	}
	public void setCode(String code) {
		this.code = code;
	}
	@Override
	public String toString() {
		return "IdCard [id=" + id + ", code=" + code + "]";
	}
}

Person.java

package com.cn.po;
/*
 * 个人持久化类
 */
public class Person {
	private Integer id;
	private String name;
	private Integer age;
	private String sex;
	private IdCard card; //个人关联的证件
	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;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public IdCard getCard() {
		return card;
	}
	public void setCard(IdCard card) {
		this.card = card;
	}
	@Override
	public String toString() {
		return "Person [id=" + id + ", name=" + name + ", age=" + age + ", sex=" + sex + ", card=" + card + "]";
	}
}

(4)在 com.cn.mapper 包中,创建证件映射文件 IdCardMapper.xml 和个人映射文件 PersonMapper.xml,并在两个映射文件中编写一对一关联映射查询的配置信息,如下所示:
IdCardMapper.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 
<mapper namespace="com.cn.mapper.IdCardMapper">
	<!-- 根据 id 查询证件信息 -->
	<select id="findCodeById" parameterType="Integer" resultType="IdCard">
		select * from tb_idcard where id=#{id}
	</select>
</mapper>

PersonMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 
<mapper namespace="com.cn.mapper.PersonMapper">
	<!-- 嵌套查询:通过执行另外一条 SQL 映射语句来返回预期的特殊类型 -->
	<select id="findPersonById" parameterType="Integer" resultMap="IdCardWithPersonResult">
		select * from tb_person where id=#{id}
	</select>
	<resultMap type="Person" id="IdCardWithPersonResult">
		<id property="id" column="id"/>
		<result property="name" column="name"/>
		<result property="age" column="age"/>
		<result property="sex" column="sex"/>
		<!-- 一对一:association 使用 select 属性引入另一条 SQL 语句 -->
		<association property="card" column="card_id" javaType="IdCard" 
				select="com.cn.mapper.IdCardMapper.findCodeById" />
	</resultMap>
</mapper>

在上述两个映射文件中,使用了 MyBatis 中的嵌套查询方式进行了个人及其关联的证件信息查询,因为返回的个人对象中除了基本属性外还有一个关联的 card 属性,所以需要手动编写结果映射。从映射文件 PersonMapper.xml 中可以看出,嵌套查询的方法是先执行一个简单的 SQL 语句,然后进行结果映射时,将关联对象在<association>元素中使用 select 属性执行另一条 SQL 语句(即 IDCardMapper.xml 中的 SQL)。
(5)在核心配置文件 mybatis-config.xml 中,引入 Mapper 映射文件并定义别名,如下:

<?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>
	<!-- 引入数据库连接配置文件 -->
	<properties resource="db.properties"/>
	<!-- 使用扫描包的形式定义别名 -->
	<typeAliases>
		<package name="com.cn.po"/>
	</typeAliases>
	<!-- 1.配置环境,默认的环境 id 为 mysql -->
	<environments default="mysql">
		<!-- 1.2.配置 id 为 mysql 的数据库环境 -->
		<environment id="mysql">
			<!-- 使用 JDBC 的事务管理 -->
			<transactionManager type="JDBC"/>
			<!-- 数据库连接池 -->
			<dataSource type="POOLED"> 
				<property name="driver" value="com.mysql.jdbc.Driver"/> 
				<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
				<property name="username" value="root"/> 
				<property name="password" value="123456"/>  
			</dataSource>  
		</environment>
	</environments>
	<!-- 2.配置 Mapper 的位置 -->  
	<mappers>   
		<mapper resource="com/cn/mapper/IdCardMapper.xml"/>
		<mapper resource="com/cn/mapper/PersonMapper.xml"/>
	</mappers> 
</configuration>

在上述核心配置文件中,首先引入了数据库连接的配置文件,然后使用扫描包的形式自定义别名,接下来进行环境配置,最后配置了 Mapper 映射文件的位置信息。
(6)在 com.cn.test 包中,创建测试类 MyBatisAssociatedTest,并在类中编写测试方法 findPersonByIdTest(),如下所示:

package com.cn.test;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import com.cn.po.Person;
import com.cn.utils.MybatisUtils;

/*
 * MyBatis 关联查询映射测试类
 */
public class MybatisAssociatedTest {
	/*
	 * 嵌套查询
	 */
	@Test
	public void findPersonByIdTest() {
		//1.通过工具类生成 SqlSession 对象
		SqlSession session = MybatisUtils.getSession();
		//2.使用 MyBatis 嵌套查询的方式查询 id 为 1 的人的信息
		Person person = session.selectOne("com.cn.mapper."+"PersonMapper.findPersonById",1);
		//3.输出查询结果信息
		System.out.println(person);
		//4.关闭 SqlSession
		session.close();
	}
}

在上代码中,findPersonByIdTest()方法中,首先通过 MybatisUtils 工具类获取了 SqlSession 对象,然后通过 SqlSession 对象的 selectOne() 方法获取了个人信息。运行结果如下:
image.png
从上图可以看出,使用 MyBatis 嵌套查询的方式查询了个人及其关联的身份证信息,这就是 MyBatis 中的一对一关联查询。
虽然使用嵌套查询的方式比较简单,但是从运行结果看,MyBatis 嵌套查询的方式要执行多条 SQL 语句,这对大型数据集合列表展示不是很好,因为这样可能会导致成百上千条关联的 SQL 语句被执行,从而极大地小号数据库性能并且会降低查询效率。这并不是开发人员所期望的,为此,可以使用 MyBatis 提供的嵌套结果方式,来进行关联查询。在 PersonMapper.xml 中,使用 MyBatis 嵌套结果方式进行个人及其关联的证件信息查询,所添加的代码如下所示:

<!-- 嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集 -->
<select id="findPersonById2" parameterType="Integer" resultMap="IdCardWithPersonResult2">
	select p.*,idcard.code
	from tb_person p,tb_idcard idcard
	where p.card_id=idcard.id
	and p.id=#{id}
</select>
<resultMap type="Person" id="IdCardWithPersonResult2">
	<id property="id" column="id"/>
	<result property="name" column="name"/>
	<result property="age" column="age"/>
	<result property="sex" column="sex"/>
	<association property="card" javaType="IdCard">
		<id property="id" column="card_id"/>
		<result property="code" column="code"/>
	</association>
</resultMap>

从上述代码中可以看出,MyBatis 嵌套结果的方式只编写了一条复杂的多表关联的 SQL 语句,并且在<association>元素中继续使用相关子元素进行数据库表字段和实体类属性的一一映射。
在测试类 MybatisAssociatedTest 中,编写测试方法 findPersonByIdTest2(),代码如下:

/*
 * 嵌套结果
 */
@Test
public void findPersonByIdTest2() {
	//1.通过工具类生成 SqlSession 对象
	SqlSession session = MybatisUtils.getSession();
	//2.使用 MyBatis 嵌套查询的方式查询 id 为 1 的人的信息
	Person person = session.selectOne("com.cn.mapper."+"PersonMapper.findPersonById2",1);
	//3.输出查询结果信息
	System.out.println(person);
	//4.关闭 SqlSession
	session.close();
}

运行结果如下:
image.png

提示:在使用 MyBatis 嵌套查询方式进行 MyBatis 关联查询映射时,使用 MyBatis 的延迟加载在一定程度上可以降低运行消耗并提高查询效率。MyBatis 默认没有开启延迟加载,需要在核心配置文件 mybatis-config.xml 中的<settings>元素内进行配置,具体配置方式如下:

<settings>
	<!-- 打开延迟加载的开关 -->
	<setting name="lazyLoadingEnabled" value="true" />
	<!-- 将积极加载改为延迟加载,即按需加载 -->
	<setting name="aggressiveLazyLoading" value="false" />
</settings>

在映射文件中,MyBatis 关联映射的<association>元素和<collection>元素中都已默认配置了延迟加载属性,即默认属性 fetchType="lazy"(属性 fetchType="eager"表示立即加载),所以在配置文件中开启延迟加载后,无须在映射文件中在做配置。

三、一对多

    在<resultMap>元素中,包含了一个<collection>子元素,MyBatis 就是通过该元素来处理一对多关联关系。<collection>子元素的属性大部分与<association>元素相同,但其还包含一个特殊属性---ofType。ofType 属性与 javaType 属性对应,它用于指定实体对象中集合类属性所包含的元素类型。
<collection>元素的使用也非常简单,同样可以参考如下两种示例进行配置,具体如下:

<!-- 方式一:嵌套查询 -->
<collection property="ordersList" column="id"
		ofType="com.cn.po.Orders"
		select="com.cn.mapper.OrdersMapper.selectOrders" />
<!-- 方式二:嵌套结果 -->
<collection property="ordersList" ofType="com.cn.po.Orders">
	<id property="id" column="orders_id />
	<result property="number" column="number" />
</collection>

接下来以用户和订单之间的这种一对多关联关系为例。具体步骤如下:
(1)在 mybatis 数据库中,创建两个数据表,分别为 tb_user 和 tb_orders,同时在表中预先插入几条数据,执行的 SQL 语句如下所示:

# 创建一个名称为 tb_user 的表
create table tb_user(
	id int(32) primary key auto_increment,
	username varchar(32),
	address varchar(256)
);
# 插入 3 条数据
insert into tb_user values('1','詹姆斯','克利夫兰');
insert into tb_user values('2','科比','洛杉矶');
insert into tb_user values('3','保罗','洛杉矶');
# 创建一个名称为 tb_orders 的表
create table tb_orders(
	id int(32) primary key auto_increment,
	number varchar(32) not null,
	user_id int(32) not null,
	foreign key(user_id) references tb_user(id)
);
# 插入 3 条数据
insert into tb_orders values('1','1000011','1');
insert into tb_orders values('2','1000012','1');
insert into tb_orders values('3','1000013','1');

完成上述操作后的数据库如下所示:
image.png
(2)在 com.cn.po 包中,创建持久化类 Orders 和 User,并在两个类中定义相关属性和方法,如下所示:
Orders.java

package com.cn.po;
/*
 * 订单持久化类
 */
public class Orders {
	private Integer id;			//订单id
	private String number;	//订单编号
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getNumber() {
		return number;
	}
	public void setNumber(String number) {
		this.number = number;
	}
	@Override
	public String toString() {
		return "Orders [id=" + id + ", number=" + number + "]";
	}
}

User.java

package com.cn.po;
import java.util.List;

/*
 * 用户持久化类
 */
public class User {
	private Integer id;							//用户编号
	private String username;				//用户姓名
	private String address;					//用户地址
	private List<Orders> ordersList;	//用户关联的订单
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	public List<Orders> getOrdersList() {
		return ordersList;
	}
	public void setOrdersList(List<Orders> ordersList) {
		this.ordersList = ordersList;
	}
	@Override
	public String toString() {
		return "User [id=" + id + ", username=" + username + ", address=" + address + ", ordersList=" + ordersList
				+ "]";
	}
}

(3)在 com.cn.mapper 包中,创建用户实体映射文件 UserMapper.xml,并在文件中编写一对多关联映射查询的配置,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace 表示命名空间 --> 
<mapper namespace="com.cn.mapper.UserMapper">
	<!-- 一对多:查看某一用户及其关联的订单信息
			注意:当关联查询出的列名相同,则需要使用别名区分 -->
	<select id="findUserWithOrders" parameterType="Integer" resultMap="UserWithOrdersResult">
		select u.*,o.id as orders_id,o.number
		from tb_user u,tb_orders o
		where u.id=o.user_id
		and u.id=#{id}
	</select>
	<resultMap type="User" id="UserWithOrdersResult">
		<id property="id" column="id"/>
		<result property="username" column="username"/>
		<result property="address" column="address"/>
		<!-- 一对多关联映射:collection
				ofType 表示属性集合中元素的类型,List<Orders>属性即 Orders 类 -->
		<collection property="ordersList" ofType="Orders">
			<id property="id" column="orders_id"/>
			<result property="number" column="number"/>
		</collection>
	</resultMap>
</mapper>

在上述代码中,使用了 MyBatis 嵌套结果的方式定义了一个根据用户 id 查询用户及其关联的订单信息的 select 语句。因为返回的用户对象中,包含 Orders 集合对象属性,所以需要手动编写结果映射信息。
(4)将映射文件 UserMapper.xml 的路径配置到核心配置文件 mybatis-config.xml 中,代码如下:

<mapper resource="com/cn/mapper/UserMapper.xml" />

(5)在测试类 MybatisAssociatedTest 中,编写测试方法 findUserTest(),代码如下:

/*
 * 一对多
 */
@Test
public void findUserTest() {
	//1.通过工具类生成 SqlSession 对象
	SqlSession session = MybatisUtils.getSession();
	//2.使用 MyBatis 嵌套查询的方式查询 id 为 1 的人的信息
	User user = session.selectOne("com.cn.mapper."+"UserMapper.findUserWithOrders",1);
	//3.输出查询结果信息
	System.out.println(user);
	//4.关闭 SqlSession
	session.close();
}

运行结果如下所示:
image.png

四、多对多

(1)创建数据表。在 mybatis 数据库中新建名称为 tb_product 和 tb_ordersitem 的两个数据表,同时在表中预先插入几条数据,其执行的 SQL 语句如下所示。

# 创建一个名称为 tb_product 的表
create table tb_product(
	id int(32) primary key auto_increment,
	name varchar(32),
	price double
);
# 插入 3 条数据
insert into tb_product values('1','Java 基础入门','44.5');
insert into tb_product values('2','Java Web 程序开发入门','38.5');
insert into tb_product values('3','SSM 框架整合实践','50');
# 创建一个名为 tb_ordersitem 的中间表
create table tb_ordersitem(
	id int(32) primary key auto_increment,
	orders_id int(32),
	product_id int(32),
	foreign key(orders_id) references tb_orders(id),
	foreign key(product_id) references tb_product(id)
);
# 插入 3 条数据
insert into tb_ordersitem values('1','1','1');
insert into tb_ordersitem values('2','1','3');
insert into tb_ordersitem values('3','3','3');

执行完上述操作后数据库表如下所示:
image.png
(2)在 com.cn.po 包中,创建持久化类 Product,并在类中定义相关属性和方法,如下所示:
Product.java

package com.cn.po;
import java.util.List;

/*
 * 商品持久化
 */
public class Product {
	private Integer id;					//商品 id
	private String name;				//商品名称
	private Double price;				//商品单价
	private List<Orders> orders;	//与订单的关联属性
	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;
	}
	public Double getPrice() {
		return price;
	}
	public void setPrice(Double price) {
		this.price = price;
	}
	public List<Orders> getOrders() {
		return orders;
	}
	public void setOrders(List<Orders> orders) {
		this.orders = orders;
	}
	@Override
	public String toString() {
		return "Product [id=" + id + ", name=" + name + ", price=" + price + ", orders=" + orders + "]";
	}
}

除了在商品持久化类中需要添加订单的集合属性外,还需要在订单持久化类(Orders.java)中增加商品集合的属性及其对应的 getter/setter 方法,同时为了方便查看输出结果,需要重写 toString() 方法,Orders 类中添加的代码如下:

//关联商品集合信息
private List<Product> productList;
//省略 getter/setter 方法,以及重写的 toString() 方法

(3)在 com.cn.mapper 包中,创建订单实体映射文件 OrdersMapper.xml 和商品实体映射文件 ProductMapper.xml,对两个映射文件进行编辑后,如下所示:
OrdersMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace 表示命名空间 --> 
<mapper namespace="com.cn.mapper.OrdersMapper">
	<!-- 一对多:查看某一用户及其关联的订单信息
			注意:当关联查询出的列名相同,则需要使用别名区分 -->
	<select id="findOrdersWithPorduct" parameterType="Integer" resultMap="OrdersWithProductResult">
		select * from tb_orders where id=#{id}
	</select>
	<resultMap type="Orders" id="OrdersWithProductResult">
		<id property="id" column="id"/>
		<result property="number" column="number"/>
		<!-- 一对多关联映射:collection
				ofType 表示属性集合中元素的类型,List<Orders>属性即 Orders 类 -->
		<collection property="productList" column="id" ofType="Product"
			select="com.cn.mapper.ProductMapper.findProductById">
		</collection>
	</resultMap>
</mapper>

在上代码中,使用嵌套查询的方式定义了一个 id 为 findOrdersWithPorduct 的 select 语句来查询订单及其关联的商品信息。在<resultMap>元素中使用了<collection>元素来映射多对多的关联关系,其中 property 属性表示订单持久化类中的商品属性,ofType 属性表示集合中的数据为 Product 类型,而 column 的属性值会作为参数执行 ProductMapper 中定义的 id 为findProductById 的执行语句来查询订单中的商品信息。
ProductMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace 表示命名空间 --> 
<mapper namespace="com.cn.mapper.ProductMapper">
	<!-- 一对多:查看某一用户及其关联的订单信息
			注意:当关联查询出的列名相同,则需要使用别名区分 -->
	<select id="findProductById" parameterType="Integer" resultType="Product">
		select * from tb_product where id in(
			select product_id from tb_ordersitem where orders_id = #{id}
		)
	</select>
</mapper>

上代码中,定义了一个 id 为 findProductById 的执行语句,该执行语句中的 SQL 会根据订单 id 查询与该订单所关联的商品信息。由于订单和商品是多对多的关联关系,所以需要通过中间表来查询商品信息。
(4)将新创建的映射文件 OrdersMapper.xml 和 ProductMapper.xm 的文件路径配置到核心配置文件 mybatis-config.xml 中,代码如下:

<mapper resource="com/cn/mapper/OrdersMapper.xml" />
<mapper resource="com/cn/mapper/ProductMapper.xml" />

(5)在测试类 MybatisAssociatedTest 中,编写多对多关联查询的测试方法 findOrdersTest(),代码如下:

/*
 * 多对多
 */
@Test
public void findOrdersTest() {
	//1.通过工具类生成 SqlSession 对象
	SqlSession session = MybatisUtils.getSession();
	//2.使用 MyBatis 嵌套查询的方式查询 id 为 1 的人的信息
	Orders orders = session.selectOne("com.cn.mapper."+"OrdersMapper.findOrdersWithProduct",1);
	//3.输出查询结果信息
	System.out.println(orders);
	//4.关闭 SqlSession
	session.close();
}

运行结果:
image.png
从图中可以看出,使用 MyBatis 嵌套查询的方式执行了两条 SQL 语句,并查询出了订单及其关联的商品信息,若使用嵌套结果的方式,代码则如下所示:

<!-- 多对多嵌套结果查询:查询某订单及其关联的商品详情 -->
<select id="findOrdersWithProduct2" parameterType="Integer"
	    resultMap="OrdersWithProductResult2">
	select 0.*,p.id as pid,p.name,p.price
	from tb_orders o,tb_product p,tb_ordersitem oi
	where oi.orders_id=o.id
	and oi.product_id=p.id
	and o.id=#{id}
</select>
<!-- 自定义手动映射类型 -->
<resultMap type="Orders" id="OrdersWithProductResult2">
	<id property="id" column="id" />
	<result property="number" column="number" />
	<!-- 多对多关联映射:collection -->
	<collection property="productList" ofType="Product">
		<id property="id" column="pid" />
		<result property="name" column="name" />
		<result property="price" column="price" />
	</collection>
</resultMap>
内事不懂问百度,外事不懂问谷歌~