目录
在实际应用中,我们常常会遇到数据库中的字段和Java实体中的属性名不一致的情况,或在多表查询时需要将多个表的数据与实体属性关联起来的情况,此时就需要使用resultMap进行结果映射了。
在这里引用一下Mybatis官网对resultMap的介绍:
resultMap 元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作。实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份resultMap 能够代替实现同等功能的数千行代码。ResultMap的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。
既然官网都说它是最重要最强大的元素,那就让我们来看看它重要在哪里,强大在哪里吧!
1.回顾resultType
1.1 使用回顾
在此之前,先说一说我们前面几篇博客用到的一个关键字resultType
前面我们写过这样的查询语句:
<select id="selectById" resultType="com.yky.springboot.entities.User">
SELECT * FROM `user` WHERE id = #{id}
</select>
对应的实体类是这样的:
package com.yky.springboot.entities;
import java.io.Serializable;
import java.util.Date;
public class User implements Serializable {
private Long id;
private String name;
private String phone;
private Date birthday;
Getter、Setter方法....
toString方法...
}
数据库中的字段是这样的:
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(100) DEFAULT NULL COMMENT '姓名',
`phone` varchar(20) DEFAULT NULL COMMENT '手机号',
`birthday` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '生日',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
可以看到,数据表中的字段名和Java实体类中的字段名完全一致。此时我们便可以直接用resultType来指定将SQL执行结果映射到com.yky.springboot.entities.User类。
1.2 简化全类名
当然了,重复的写完整的类名看起来并不是很优雅,此时我们可以使用类型别名来解决,Mybatis为我们提供了typeAlias关键字,typeAlias需要写在Mybatis的全局配置文件mybatis-config.xml中。在resources下创建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>
<typeAliases>
<typeAlias type="com.yky.springboot.entities.User" alias="User"></typeAlias>
</typeAliases>
</configuration>
还需要在yml文件中指定一下Mybatis全局配置文件所在路径:
mybatis:
#配置mybatis映射文件路径
mapper-locations: classpath:mapper/*.xml
#配置mybatis全局配置文件所在路径
config-location: classpath:mybatis-config.xml
此时同样的SQL语句可以这样写:
<select id="selectById" resultType="User">
SELECT * FROM `user` WHERE id = #{id}
</select>
1.3 局限性
1. 数据库字段需要与实体类字段完全一致
这一点不用多说,毕竟字段不一样的话Mybatis是不知道怎么匹配的。
2. 对多表关联不友好甚至根本满足不了多表关联需求(一对一、一对多、多对多)
比如有一个员工类:Employee
有一个部门类:Department
部门类中有一个List<Employee> employees属性,包含部门所有员工,在这里部门与员工之间属于一对多的关系。
有以下需求:
[1] 只通过一条多表查询语句,直接查询到部门信息,以及当前部门的所有员工
[2] 将上述SQL语句查询到的信息封装到Department类中(employees保存所有员工列表)
显然这样做使用resultType是满足不了的。
鉴于resultType有种种限制,resultMap便应运而生了。
2.resultMap简单使用
resultMap最简单的应用场景是:解决数据库字段与实体属性名不一致的问题。
接下来直接上代码
有员工类:
public class Employee implements Serializable {
/**
* 主键id
*/
private Long id;
/**
* 姓名
*/
private String name;
/**
* 工号
*/
private String number;
/**
* 部门编号
*/
private Long departmentId;
/**
* 薪资
*/
private Double salary;
Getter(),Setter().....
toString()....
}
有数据表:
CREATE TABLE `employee` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`employee_name` varchar(255) NOT NULL,
`number` varchar(255) NOT NULL,
`department_id` int(11) NOT NULL,
`salary` decimal(10,2) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
很显然,数据表中的列名与实体类中的字段名并不一致,这时就需要用到resultMap来指定数据表中的字段与实体属性字段的一一对应关系了。
Mapper接口代码:
@Mapper
public interface EmployeeMapper {
List<Employee> selectAll();
}
写在EmployeeMapper.xml中的resultMap代码:
<resultMap id="empMap" type="com.yky.springboot.entities.Employee">
<!--主键需要使用id标签单独写,可以提高性能-->
<id column="id" property="id"/>
<!--普通字段直接使用result标签-->
<result column="employee_name" property="name"/>
<result column="number" property="number"/>
<result column="department_id" property="departmentId"/>
<result column="salary" property="salary"/>
</resultMap>
写在EmployeeMapper.xml中的SQL查询语句代码:
<select id="selectAll" resultMap="empMap">
SELECT * FROM employee
</select>
上面我所举的例子是resultMap的最简单的应用了,resultMap的高级应用则体现在了多表联合映射上。
3.resultMap高级结果映射
resultMap高级结果映射,即在多表联合查询时,将结果联合映射到目标实体中。这里的目标实体通常包含其他实体对象、集合等元素。常用在一对一,一对多、多对一、多对多的关系表中。
在此之前,先列出resultMap的子元素(摘自官方教程):
- constructor - 用于在实例化类时,注入结果到构造方法中-----当创建实体类时需要传构造参数时使用
。idArg - ID 参数;标记出作为 ID 的结果可以帮助提高整体性能
。arg - 将被注入到构造方法的一个普通结果 - id – 一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能-----标示主键id,可以提高性能
- result – 注入到字段或 JavaBean 属性的普通结果-----映射普通字段
- association – 一个复杂类型的关联;许多结果将包装成这种类型------映射实体类内部包含的其他实体类
。嵌套结果映射 – 关联可以是 resultMap 元素,或是对其它结果映射的引用 - collection – 一个复杂类型的集合------映射实体类中包含的集合
。嵌套结果映射 – 集合可以是 resultMap 元素,或是对其它结果映射的引用 - discriminator – 使用结果值来决定使用哪个 resultMap-----根据判断条件,有选择的映射
。case – 基于某些值的结果映射- 嵌套结果映射 – case 也是一个结果映射,因此具有相同的结构和元素;或者引用其它的结果映射
在这里,我们不去讨论数据表的一对一、一对多、多对一、多对多关系。我们只试图通过下面两节展示一个稍微复杂一点的例子来演示resultMap的高级用法。
4.一条SQL语句实现多表关联映射
4.1 实体类创建
假设我们需要定义一个实体类来表示一个大学生,需要包含以下信息:
- 姓名、性别、年龄、学号,这些属于基本信息
- 所加入的社团,这里需要是一个包含社团对象的集合
- 所属专业(在这里不考虑多学位情况),这里需要