Mybatis 强大的结果映射器ResultMap
1. 前言
resultMap
元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBCResultSets
数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作。实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份resultMap
能够代替实现同等功能的数千行代码。ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。
resultMap
可以将查询到的复杂数据,比如多张表的数据、一对一映射、一对多映射等复杂关系聚合到一个结果集当中。日常的业务开发通常都会和它打交道,今天就对 resultMap
进行一个详细讲解。文末有 DEMO
2. resultMap
接下来我们来看看 resultMap
是如何进行映射的。
2.1 Getter/Setter 注入
我们声明一个数据库对应的实体类:
/*** @author felord.cn* @since 16:50**/
@Data
public class Employee implements Serializable {private static final long serialVersionUID = -7145891282327539285L;private String employeeId;private String employeeName;private Integer employeeType;
}
那么它对应的 resultMap
为:
<mapper namespace="cn.felord.mybatis.mapper.EmployeeMapper"><resultMap id="EmployeeMap" type="cn.felord.mybatis.entity.Employee"><id column="employee_id" property="employeeId"/><result column="employee_name" property="employeeName"/><result column="employee_type" property="employeeType"/></resultMap>
</mapper>
我们来解释这些配置的属性:
<mapper namespace="全局唯一的名称空间"><resultMap id="本namespace下唯一" type="对应映射的实体"><id column="数据库主键字段名或者别名,使用它提高整体性能" property="对应实体属性"/><result column="数据库字段名或者别名" property="对应实体属性"/></resultMap>
</mapper>
以上方式是通过 Getter 和 Setter 方法进行注入,也就是实体类必须有无参构造,对应属性必须有Getter 和 Setter 方法。
2.2 构造注入
Getter 和 Setter 方法进行注入是我们最常用的方式。但是 Mybatis 同样支持构造注入,如果 Employee
存在如下构造方法:
public Employee(String employeeId, String employeeName, Integer employeeType) {this.employeeId = employeeId;this.employeeName = employeeName;this.employeeType = employeeType;
}
那么对应的 resultMap
可以这样写:
<mapper namespace="cn.felord.mybatis.mapper.EmployeeMapper"><resultMap id="EmployeeMap" type="cn.felord.mybatis.entity.Employee"><constructor><idArg column="employee_id" javaType="String"/><arg column="employee_name" javaType="String"/><arg column="employee_type" javaType="String"/></constructor></resultMap>
</mapper>
细心的同学发现这里并没有 property
属性,其实当你不声明property
属性时会按照构造方法的参数列表顺序进行注入。
在 Mybatis 3.4.3 引入了 name
属性后我们就可以打乱 constructor
标签内的 arg
元素的顺序了。
<mapper namespace="cn.felord.mybatis.mapper.EmployeeMapper"><resultMap id="EmployeeConstructorMap" type="cn.felord.mybatis.entity.Employee"><constructor><idArg column="employee_id" javaType="String" name="employeeId"/><!-- 你可以不按参数列表顺序添加--><arg column="employee_type" javaType="Integer" name="employeeType"/><arg column="employee_name" javaType="String" name="employeeName"/></constructor></resultMap>
</mapper>
2.3 继承关系
像 Java 中的类一样,resultMap
也是可以继承的。下面是两个有继承关系的 Java 类:
那么 RegularEmployee
的 resultMap
就可以这么写:
<resultMap id="RegularEmployeeMap" extends="EmployeeMap" type="cn.felord.mybatis.entity.RegularEmployee"><result column="level" property="level"/><result column="job_number" property="jobNumber"/><association property="department" javaType="cn.felord.mybatis.entity.Department"><id column="department_id" property="departmentId"/><result column="department_name" property="departmentName"/><result column="department_level" property="departmentLevel"/></association>
</resultMap>
跟 Java 的继承关键字一样使用 extends
来进行继承。
2.4 一对一关联
明眼人会看出来 2.3 最后一个 resultMap
示例中有一个 association
标签。这个用来做什么用呢?打个比方,每一个正式员工 RegularEmployee
会对应一个部门 Department
,业务中会有把这种 一对一 关系查询出来的需求。所以 association
就派上了用场。
<resultMap id="RegularEmployeeMap" extends="EmployeeMap" type="cn.felord.mybatis.entity.RegularEmployee"><result column="level" property="level"/><result column="job_number" property="jobNumber"/><association property="属性名称" javaType="对应的Java类型"><id column="department_id" property="departmentId"/><result column="department_name" property="departmentName"/><result column="department_level" property="departmentLevel"/></association>
</resultMap>
association
可以继续嵌套下去,有可能关联的对象中还有一对一关系。
2.5 一对多关联
有一对一关联,自然会有一对多关联。我们反客为主,一个部门有多个员工,我们可能需要查询一个部门的信息以及所有员工的信息装载到 DepartmentAndEmployeeList
中去。
/*** @author felord.cn* @since 15:33**/
public class DepartmentAndEmployeeList extends Department {private static final long serialVersionUID = -2503893191396554581L;private List<Employee> employees;public List<Employee> getEmployees() {return employees;}public void setEmployees(List<Employee> employees) {this.employees = employees;}
}
我们可以在 resultMap
中使用 collection
关键字来处理一对多映射关系:
<resultMap id="DepartmentAndEmployeeListMap" extends="DepartmentMap"type="cn.felord.mybatis.entity.DepartmentAndEmployeeList"><collection property="employees" ofType="cn.felord.mybatis.entity.RegularEmployee"><id column="employee_id" property="employeeId"/><result column="employee_name" property="employeeName"/><result column="level" property="level"/><result column="job_number" property="jobNumber"/></collection>
</resultMap>
2.6 鉴别器
大家都知道,员工并不都是正式工,还有临时工。有时候我们也期望能够将这两种区分开来,至于原因你懂的。不深入讨论这个问题了。就这个需求而言我们的映射关系又复杂了,我们需要根据某个条件来判断哪条数据是正式工,哪条数据是临时工,然后分别装入下面这个实体类的 regularEmployees
、temporaryEmployees
中。
/*** @author felord.cn* @since 15:33**/
public class DepartmentAndTypeEmployees extends Department {private static final long serialVersionUID = -2503893191396554581L;private List<RegularEmployee> regularEmployees;private List<TemporaryEmployee> temporaryEmployees;// getter setter
}
鉴别器(discriminator
)元素就是被设计来应对这种情况的,另外也能处理其它情况,例如类的继承层次结构。鉴别器的概念很好理解——它很像 Java 语言中的 switch 语句。
为此我们需要在 Employee
类中增加一个 int
类型的 employeeType
属性来区分正式工和临时工,其中 1
代表正式工,而 0
代表临时工。然后我们来编写查询 DepartmentAndTypeEmployees
的 resultMap
:
<resultMap id="DepartmentAndTypeEmployeesMap" extends="DepartmentMap"type="cn.felord.mybatis.entity.DepartmentAndTypeEmployees"><collection property="regularEmployees" ofType="cn.felord.mybatis.entity.RegularEmployee"><discriminator javaType="int" column="employee_type"><case value="1"><id column="employee_id" property="employeeId"/><result column="employee_name" property="employeeName"/><result column="employee_type" property="employeeType"/><result column="level" property="level"/><result column="job_number" property="jobNumber"/></case></discriminator></collection><collection property="temporaryEmployees" ofType="cn.felord.mybatis.entity.TemporaryEmployee"><discriminator javaType="int" column="employee_type"><case value="0"><id column="employee_id" property="employeeId"/><result column="employee_name" property="employeeName"/><result column="employee_type" property="employeeType"/><result column="company_no" property="companyNo"/></case></discriminator></collection>
</resultMap>
切记一定是先声明 DepartmentAndTypeEmployees
的两个 List
,然后在 collection
标签内部使用 discriminator
标签。
这里很容易犯以下错误,下面的写法满足不了上述需求的:
<resultMap id="DepartmentAndTypeEmployeesMap" extends="DepartmentMap"type="cn.felord.mybatis.entity.DepartmentAndTypeEmployees"><discriminator javaType="int" column="employee_type"><case value="1"><collection property="regularEmployees" ofType="cn.felord.mybatis.entity.RegularEmployee"><!--省略--></collection></case><case value="0"><collection property="temporaryEmployees" ofType="cn.felord.mybatis.entity.TemporaryEmployee"><!--省略--></collection></case></discriminator></resultMap>
这种写法的意思是:当发现该条数据中 employee_type=1
时,就新建一个 List<RegularEmployee>
并把该条数据放进去,每次都会新建一个 List<RegularEmployee>
;当employee_type=0
时也一样。这样的话就会返回一个 List<DepartmentAndTypeEmployees>
。
3. 总结
resultMap
能够满足大部分业务场景对于数据映射的需求,今天我们对 Mybatis 中 resultMap
的一些用法进行了讲解,其实 resultMap
还有一些有用的属性,基于篇幅的原因这里不再讲解,可阅读 Mybatis 官方文档。但是请注意虽然 resultMap
功能强大,一定要合理使用,级联过于复杂会影响后期维护和性能。比如当一对多映射时,多的一方如果数据条数过大,会增加内存消耗和读写性能。希望今天的文章对你使用 resultMap
有所帮助,更及时的技术资讯请多多关注:码农小胖哥。
往期推荐
面试:那些问哭你的Redis分布式锁!
HTTP/3 来了 !HTTP/2 还没怎么用起来呢,先一起扫个盲吧!
Nacos 1.3.0 发布,一个修炼内功的版本:全新内核构建!
疯抢当当图书 618 优惠码,花 120 买 300
万字超强图文讲解 AQS 以及 ReentrantLock 应用
架构师究竟要不要写代码?
面试:String 五连杀 !你还满血吗 ?
本文章的 DEMO ,可关注下方公众号,回复 resultMap 获取。
Mybatis 强大的结果映射器ResultMap相关推荐
- mybatis 一对多_Mybatis 强大的结果集映射器resultMap
1. 前言 resultMap 元素是 MyBatis 中最重要最强大的元素.它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC ...
- Could not find resource——mybatis 找不到映射器xml文件
今天用IDEA写Mybatis的时候,测试报了如图所示的错,恶心死我了,后来解决了,总结一下,防止下回跳坑,当然,也是做一个分享,如果有朋友遇到这个错,希望有所帮助 Error parsing SQL ...
- MyBatis学习之映射器Mapper(接口映射器+xml映射文件)
Table of Contents 01 MyBatis映射器: 1.1 接口映射器+xml映射器 1.2 接口映射器+注解 02 接口映射器+xml映射器 方式 2.1 mybatis配置文件 引 ...
- 深入理解MyBatis的原理(四):映射器的用法
前言:继续深入学习 mybatis 的用法及原理,还是先会用再学习原理. 映射器的主要元素有:select.insert.update.delete.parameterMap(即将被删除,不建议使用) ...
- 深入浅出MyBatis:「映射器」全了解
本篇文章是「深入浅出MyBatis:技术原理与实践」书籍的总结笔记. 上一篇总结了MyBatis的配置,详细说明了各个配置项,其中提到了映射器,它是MyBatis最强大的工具,也是使用最多的工具. 通 ...
- mybatis的mapper.xml文件中含有中文注释时运行出错,mybatis配置优化和别名优化 mybatis配置之映射器说明
记录一个发现的小问题,刚刚在UserMapper.xml文件中有一段中文注释掉的内容: <!-- <resultMap id="Usermap" type=" ...
- Mybatis基于XML配置SQL映射器(二)
Mybatis之XML注解 之前已经讲到通过 mybatis-generator 生成mapper映射接口和相关的映射配置文件: 下面我们将详细的讲解具体内容 首先我们新建映射接口文档 sysUse ...
- Mybatis中强大的功能元素:resultMap
转载自 Mybatis中强大的功能元素:resultMap 前言 在Mybatis中,有一个强大的功能元素resultMap.当我们希望将JDBC ResultSets中的数据,转化为合理的Java ...
- MyBatis数据库连接的基本使用-补充Mapper映射器
补充 Mapper映射器的使用: Mapper映射器,google添加.Mapper映射器是将mapper.xml中配置的sql id,parameterType和resultMap按照规则一一映射到 ...
最新文章
- php curl for win7_解决windows7X64环境下开启PHP_Curl wamp curl PHP开启CURL无反应
- JAVA API实现HDFS操作(二)操作函数
- powerBi odbc 连接impala 实现自助分析
- javascript怎么监听 form.submit事件
- 时间序列 线性回归 区别_时间序列分析的完整介绍(带R)::线性过程I
- 给mysql salve从库复制授权_MySQL主从复制
- php7类型约束,类型约束 - PHP 7 中文文档
- Web前端开发-网页制作零基础入门-Dreamweaver2019+HTML+CSS视频教程
- 《汇编语言》学习(十三)int指令
- visio 去除“讨厌”的自动捕捉
- 有符号二进制数的减法
- 第28届奥运会奖牌榜
- 安卓 10 周岁了:这些消失的经典 APP 你还记得吗?
- 迅雷赚钱宝和优酷路由宝赚钱的原理
- 【ASH】如何导出视图DBA_HIST_ACTIVE_SESS_HISTORY的查询结果数据
- THz:短距离室内电信上的研究
- FLUENT UDF案例一
- RPA机器人有哪三大优势?
- CocosCreator 渲染
- 如何避免程序媛被叫做“程序员鼓励师”?
热门文章
- golang 1.18 新增泛型 简介
- Git Push 避免用户名和密码方法
- VS 的makefile工程
- Windows的驱动开发模型
- VC6如何使用VS2005中的CImage类功能
- 在 Windows 上像 Linux 一样使用命令
- int*p[ ]与int(*p)[ ]的不同
- rpm包备份命令linux,RPM常用命令介绍 - Linux就该这么学的个人空间 - OSCHINA - 中文开源技术交流社区...
- pta简单实现x的n次方_PTA-2017实验2.4 函数
- sql盲注特点_SQL注入第二章——access,mssql,oracle