【Mybatis用法】Mybatis 高级结果映射,ResultMap Association,mybatis的一对多,多对一,以及多对多的配置和使用

简介: 【Mybatis用法】Mybatis 高级结果映射,ResultMap Association,mybatis的一对多,多对一,以及多对多的配置和使用

一、背景描述

需求:查询任务逾期记录时,把任务相关信息查询出来;

表设计:任务相关信息是一张表(uoa_assignment),任务逾期记录是一张表(uoa_assignment_overdue_log);外键是任务主键(id);

JavaBean:class Assignment, class AssignmentOverdueLog; class AssignmentOverdueLog中包含class Assignment对象。

目的:在查询任务逾期记录时,两张表关联查询出来之后,想要把Assignment的结果集映射到AssignmentOverdueLog中。

两个JavaBean对象如下:AssignmentOverdueLog对象中包含一个Assignment对象。

在查询任务逾期记录时,两张表关联查询出来之后,想要把Assignment的结果集映射到AssignmentOverdueLog中。

二、解决方案

mapper.xml中正确的写法

方法1

写两个<resultMap></resultMap>,通过<association>标签关联起来,然后在查询的sql语句结果集映射中填写外层的<resultMap>的属性id。

在上面的例子中,您会看到AssignmentOverdueLog联合一个“assignmentResultMap”结果映射来加载Assignment实例。

重点提示:id元素在嵌套结果映射中扮演了非常重要的角色,您应该总是指定一个或多个属性来唯一标识这个结果集。事实上,如果您没有那样做,MyBatis也会工作,但是会导致严重性能开销。选择尽量少的属性来唯一标识结果,而使用主键是最明显的选择(即使是复合主键)。

上面的例子使用一个扩展的resultMap 元素来联合映射。这可使Assignment结果映射可重复使用

然后,如果您不需要重用它,您可以直接嵌套这个联合结果映射。这就是另外一种写法了。

方法2

方法3

上面的例子,首先执行<select id=“queryListByLastMonth”>,执行结果存放到<resultMap id=“assignmentOverdueLogMap”>结果映射中。“assignmentOverdueLogMap”是一个AssignmentOverdueLog类型,从<select id=“queryListByLastMonth”>查出的数据都会自动赋值给”assignmentOverdueLogMap”的与列名匹配的属性,这时assignment_id,responsibleUser,responsibleName等就被赋值了。同时“assignmentOverdueLogMap”还有一个关联属性"assignment",执行嵌套查询select=”getAssignment”后,Assignment对象的属性id,type,transactType,title,description等也被赋于数据库中匹配的值。

我们使用两个select语句:一个用来加载AssignmentOverdueLog,另一个用来加载Assignment。AssignmentOverdueLog的resultMap 描述了使用“getAssignment”语句来加载Assignment的属性。

如果列名和属性名称相匹配的话,所有匹配的属性都会自动加载。

虽然这个方法简单,但是对于大数据集或列表查询,就非常不友好了。此问题被称为“N+1 选择问题”(N+1 Selects Problem)。概括地说,N+1选择问题是这样产生的:

1、您执行单条SQL语句去获取一个列表的记录( “+1”)。

2、对列表中的每一条记录,再执行一个联合select 语句来加载每条记录更加详细的信息(“N”)。

这个问题会导致成千上万的SQL语句的执行,因此并非总是可取的。

上面的例子,MyBatis可以使用延迟加载这些查询,因此这些查询立马可节省开销。然而,如果您加载一个列表后立即迭代访问嵌套的数据,这将会调用所有的延迟加载,因此性能会变得非常糟糕。

鉴于此,这有另外一种方式。联合嵌套结果集(Nested Results for Association),也就是上面的方法1和方法2两种方式。

会用到ResultMap联合嵌套结果集(Nested Results for Association)

ResultMap 一个可以映射联合嵌套结果集到一个适合的对象视图上的ResultMap 。这是一个替代的方式去调用另一个select 语句。它允许您去联合多个表到一个结果集里。这样的结果集可能包括冗余的、重复的需要分解和正确映射到一个嵌套对象视图的数据组。简言之,MyBatis 让您把结果映射‘链接’到一起,用来处理嵌套结果。也就是上面的方法1和方法2两种方式。

 

在上面的例子中您已经看到如果处理“一对一”(“has one”)类型的联合查询。但是对于“一对多”(“has many”)的情况如果处理呢?这个问题在下一节讨论:(待补充........)。

 

 

 

拓展:

<association property="assignment" javaType="com.iot.uoa.assignment.entity.Assignment">
  <result property="id" column="id"/>
  <result property="type" column="task_type"/>
  <result property="title" column="title"/>
  <result property="responsibleUser" column="responsible_user"/>
  <result property="responsibleName" column="responsible_name"/>
  <result property="transactType" column="transact_type"/>
  <result property="description" column="description"/>
  <result property="taskLevel" column="task_level"/>
</association>

Association元素处理“has-one”(一对一)这种类型关系。比如在我们的例子中,一个AssignmentOverdueLog有一个Assignment。联合映射与其它的结果集映射工作方式差不多,指定property、column、javaType(通常MyBatis会自动识别)、jdbcType(如果需要)、typeHandler。

不同的地方是您需要告诉MyBatis 如何加载一个联合查询。MyBatis使用两种方式来加载:

Select:通过执行另一个返回预期复杂类型的映射SQL语句(即引用外部定义好的SQL语句块)。

Results:通过嵌套结果映射(nested result mappings)来处理联接结果集(joined results)的重复子集。

首先,让我们检查一下元素属性。正如您看到的,它不同于普通只有selectresultMap属性的结果映射。

属性 描述
property 映射数据库列的字段或属性。如果JavaBean 的属性与给定的名称匹配,就会使用匹配的名字。否则,MyBatis 将搜索给定名称的字段。两种情况下您都可以使用逗点的属性形式。比如,您可以映射到”username”,也可以映射到更复杂点的”address.street.number”。
column

数据库的列名或者列标签别名。与传递给resultSet.getString(columnName)的参数名称相同。

注意: 在处理组合键时,您可以使用column= “{prop1=col1,prop2=col2}”这样的语法,设置多个列名传入到嵌套查询语句。这就会把prop1和prop2设置到目标嵌套选择语句的参数对象中。

javaType 完整java类名或别名(参考上面的内置别名列表)。如果映射到一个JavaBean,那MyBatis 通常会自行检测到。然而,如果映射到一个HashMap,那您应该明确指定javaType 来确保所需行为。
jdbcType 支持的JDBC类型列表中列出的JDBC类型。这个属性只在insert,update 或delete 的时候针对允许空的列有用。JDBC 需要这项,但MyBatis 不需要。如果您直接编写JDBC代码,在允许为空值的情况下需要指定这个类型。
typeHandler 我们已经在文档中讨论过默认类型处理器。使用这个属性可以重写默认类型处理器。它的值可以是一个TypeHandler实现的完整类名,也可以是一个类型别名。

显示详细信息

联合嵌套选择(Nested Select for Association)

select 通过这个属性,通过ID引用另一个加载复杂类型的映射语句。从指定列属性中返回的值,将作为参数设置给目标select 语句。表格下方将有一个例子。注意:在处理组合键时,您可以使用column=”{prop1=col1,prop2=col2}”这样的语法,设置多个列名传入到嵌套语句。这就会把prop1和prop2设置到目标嵌套语句的参数对象中。

 

 

 

完结!

 

相关文章
|
30天前
|
SQL 缓存 Java
mybatis 一对多查询
mybatis 一对多查询
31 0
|
30天前
|
Java 数据库连接 mybatis
mybatis的一对多
mybatis的一对多
|
30天前
|
SQL Java
【JAVA进阶篇教学】第九篇:MyBatis-Plus用法介绍
【JAVA进阶篇教学】第九篇:MyBatis-Plus用法介绍
|
30天前
|
缓存 Java 数据库连接
MyBatis三级缓存实战:高级缓存策略的实现与应用
MyBatis三级缓存实战:高级缓存策略的实现与应用
45 0
MyBatis三级缓存实战:高级缓存策略的实现与应用
|
30天前
|
存储 XML Java
mybatis使用内部类处理一对多类型数据2
mybatis使用内部类处理一对多类型数据2
17 0
|
30天前
|
XML SQL Java
mybatis的一对多,多对一,以及多对对的配置和使用
mybatis的一对多,多对一,以及多对对的配置和使用
20 2
|
30天前
|
XML Java 数据库连接
mybatis的resultMap完美解析
mybatis的resultMap完美解析
34 0
|
30天前
|
SQL Java 数据库连接
mybatis关联配置(一对多配置)
mybatis关联配置(一对多配置)
16 1
|
30天前
|
Java 数据库连接 网络安全
mybatis使用全注解的方式案例(包含一对多关系映射)
mybatis使用全注解的方式案例(包含一对多关系映射)
14 0
|
28天前
|
算法 Java 数据库连接
Spring+MySQL+数据结构+集合,Alibaba珍藏版mybatis手写文档
Spring+MySQL+数据结构+集合,Alibaba珍藏版mybatis手写文档