MyBatis-多表查询

MyBatis-多表查询

  • 多表查询的sql语句仍然需要我们自己编写(连接查询)

  • 自己设计存储数据的实体类,承接多个表的查询结果

  • 使用自定义结果集映射(resultMap)


多表之间的关系

在数据库中,多表之间存在多个关系:

  • 一对一
  • 一对多
  • 多对多

但在实体类中,多实体类中只看单向的关系,比如:

一个客户对应多个订单,就是对多的关系

一个订单对应多个客户,就是对一的关系

在微头条项目中,我们学会了值对象(VO),使用这种对象可以接受数据库多表查询的结果

而现在,我们解决多表查询的方法是,将一个实体类对象作为属性放到另一个实体类中

如果为对一关系,比如上面的例子,就在订单实体类中存放一个客户实体类对象作为属性

如果为对多关系,比如上面的例子,就在客户实体类中存放一个类型为客户实体类的List集合作为属性

在实际开发中,只有在查询所需时才修改实体类,并且修改时只做一个实体类的修改,其对应的不需要考虑


对一映射

pojo
1
2
3
4
5
@Data
public class Customer {
private int customerId;
private String customerName;
}
1
2
3
4
5
6
7
@Data
public class Order {
private Integer orderId;
private String orderName;
private int customerId;
private Customer customer;
}
mapper接口
1
2
3
public interface OrderMapper {
Order queryOrderById(Integer id);
}
mapper.xml

使用resultMap标签为查询结果做映射

通过association,即可为对象中的对象属性做映射,在标签中套用子标签即可赋值对象属性的属性

  • property属性:属性名
  • javaType:类的全限定符或类别名
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.xiaobai.mapper.OrderMapper">
<resultMap id="orderMap" type="order">
<id column="order_id" property="orderId"/>
<result column="order_name" property="orderName"/>
<result column="customer_id" property="customerId"/>
<!--给对象赋值-->
<association property="customer" javaType="customer">
<id column="customer_id" property="customerId"/>
<result column="customer_name" property="customerName"/>
</association>
</resultMap>

<select id="queryIdby" resultMap="orderMap">
select * from t_order tor join t_customer tur
on tor.customer_id = tur.customer_id
where tor.order_id = #{id}
</select>
</mapper>

对多映射

pojo
1
2
3
4
5
6
public class Customer {
private int customerId;
private String customerName;

private List<Order> orders;
}
1
2
3
4
5
6
public class Order {
private Integer orderId;
private String orderName;
private int customerId;
private Customer customer;
}
mapper接口
1
2
3
public interface CustomerMapper {
List<Customer> selectAllCustomer();
}
mapper.xml

使用resultMap标签为查询结果做映射

通过collection,即可为对象中的List集合属性做映射,在标签中套用子标签即可赋值集合中对象属性的属性

  • property属性:属性名
  • ofType:集合的泛型,也就是集合中的对象的数据类型

注:我们在进行两个表的相互映射过程中,只考虑单向的映射关系,比如在这个例子中,我们在List集合中的order对象中也存在customer对象,但不要映射此对象,否则会出现映射循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.xiaobai.mapper.CustomerMapper">
<resultMap id="customerMapper" type="customer">
<id column="customer_id" property="customerId"/>
<result column="customer_name" property="customerName"/>
<!--映射集合对象-->
<collection property="orders" ofType="order">
<id column="order_id" property="orderId"/>
<result column="order_name" property="orderName"/>
<result column="customer_id" property="customerId"/>
</collection>
</resultMap>

<select id="selectAllCustomer" resultMap="customerMapper">
select *
from t_order tor join t_customer tur
on tor.customer_id = tur.customer_id
</select>

</mapper>

autoMapppingBehavior

配置mybatis-config.xml的setting标签,开启此功能,指定 MyBatis 应如何自动映射列到字段或属性

注:仅仅映射result也就是常规列的内容,主键列不会自动映射

value属性有三个选项值:

  • NONE:关闭自动映射
  • PARTIAL:部分映射
  • FULL:深度映射

默认情况下,resultMap只会映射一层result的标签,也就是说,不支持对一和对多映射对象属性(集合属性)

1
2
3
4
5
6
7
8
<settings>
<!-- 开启MyBaits日志输出 -->
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!-- 开启MyBaits驼峰式映射 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!--开启MyBatis自动映射列到字段或属性(单一层次)-->
<setting name="autoMappingBehavior" value="PARTIAL"/>
</settings>

value值更改为FULL,则开启深层次映射

1
2
3
4
5
6
7
8
<settings>
<!-- 开启MyBaits日志输出 -->
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!-- 开启MyBaits驼峰式映射 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!--开启MyBatis自动映射列到字段或属性(单一层次)-->
<setting name="autoMappingBehavior" value="FULL"/>
</settings>
1
2
3
4
5
6
7
8
9
10
    <resultMap id="customerMapper" type="customer">
<id column="customer_id" property="customerId"/>
<!-- <result column="customer_name" property="customerName"/>-->
<!--映射集合对象-->
<collection property="orders" ofType="order">
<id column="order_id" property="orderId"/>
<!-- <result column="order_name" property="orderName"/>-->
<!-- <result column="customer_id" property="customerId"/>-->
</collection>
</resultMap>

在进行深层次映射时,我不禁想到一个问题,深层次映射是否会导致映射循环

但仔细阅读代码发现,深层次映射也只是根据collection和association标签来进行映射

在resultMap中,当发现对象属性(集合属性)则不进行自动映射,进而寻找collection(association)标签

一个标签代表着一个对象(一个集合),这样就完美的避免了映射循环的问题


嵌套选择

<association> 标签中的 selectcolumn 属性是 MyBatis 提供的一种强大而灵活的功能,它允许你通过指定另一个 Mapper 接口的方法来加载关联对象。这种机制被称为 嵌套选择(Nested Select),它是 MyBatis 结果映射的一部分,用于处理复杂的数据关系。

<association> 标签的作用

  • property:指定要映射到的结果对象的属性名称。
  • javaType:指定该属性对应的 Java 类型。
  • column:指定从主查询结果集中提取的列名或别名,作为参数传递给子查询。
  • select:指定一个查询语句的 ID,通常是另一个 Mapper 接口中的方法名,用来执行子查询并填充关联对象。
1
2
3
4
<resultMap id="NodeVoResult" type="NodeVo">
<association property="region" javaType="Region" column="regionId" select="com.dkd.manage.mapper.RegionMapper.selectRegionById"/>
<association property="partner" javaType="Partner" column="partnerId" select="com.dkd.manage.mapper.PartnerMapper.selectPartnerById"/>
</resultMap>

在这里,mybatis会通过外键regionId和partnerId分别调用两个mapper的方法单独发送请求查询,并通过resultmap进行对象的映射

这种方式很相似在Service层调用多个Dao查询多个表,然后在Service层组织Vo返回,这里只不过是将组织Vo这一步骤放在Dao层,利用Mybatis的特性来解决



MyBatis-多表查询
http://blog.170827.xyz/2024/06/16/MyBatis-多表查询/
作者
XIAOBAI
发布于
2024年6月16日
许可协议