MyBatis 中 resultMap 详解
resultMap 是 Mybatis 最强大的元素之一,它可以将查询到的复杂数据(比如查询到几个表中数据)映射到一个结果集当中。如在实际应用中,有一个表为(用户角色表),通过查询用户表信息展示页面,在(用户表)中存在用户角色表 id ,在实际列表页的展示中,用户关注的是用户角色名称,而不是角色 id。解决此类问题可以通过 resultMap 来映射自定义结果。 使用 resultMap 做自定义结果映射,字段名可以不一致,并且还可以指定要显示的列,比较灵活,应用也广泛(推荐使用)。
resultMap 知识点
resultMap 元素用来描述如何将结果集映射到 Java 对象,使用 resultMap 对列表展示所需的必要字段来进行自动映射,特别是当数据库的字段名和实体类 POJO 中的属性名不一致的情况下,比如角色名称,字段名/列名 column 是 roleName,而 User 对象的属性名则为 userRoleName ,此时就需要做映射。
resultMap 元素的属性值和子节点
id 属性:唯一标识,此 id 值用于 select 元素 resultMap 属性的引用。
type 属性:表示该 resultMap 的映射结果类型。
result 子节点:用于标识一些简单属性,其中 column 属性表示从数据库中查询的字段名或别名, property 属性则表示查询出来的字段对应的值赋给实体对象的哪个属性。
说明:MyBatis 中在对查询进行 select 映射的时候,返回类型可以用 resultType 也可以用 resultMap ,resultType和 resultMap 有一定关联和区别,应用场景也不同。
resultType 和 resultMap 区别
resultType:直接表示返回类型,包括基础数据类型和复杂数据类型。
resultMap 则是对外部 resultMap 定义的引用,对应外部 resultMap 的 id,表示返回结果映射到哪一个 resultMap 上。它的应用场景一般是:数据库字段信息与对象属性不一致或者需要做复杂的联合查询以便自由控制映射结果。
说明:注意,MyBatis 中使用 resultType 做自动映射,一定要注意:字段名和 POJO 的属性名必须一致。若不一致,则需要给字段起别名,保证别名与属性名一致。
resultType 和 resultMap 关联
在 MyBatis 进行查询映射的时候,其实查询出来的每个字段值都放在一个对应的 Map 里面,其中键是字段名,值则是其对应的值。当 select 元素提供的返回类型属性是 resultType 的时候, MyBatis 会将 Map 里面的键值对取出赋给 resultType 所指定的对象对应的属性(即调用对应的对象里的属性的 setter 方法进行填充)。正因为如此,当使用 resultType 的时候,直接在后台就能接收到其相应的对象属性值。由此可看出,其实 MyBatis 的每个查询映射的返回类型都是 resultMap ,只是当我们提供的返回类型属性是 resultType 的时候, MyBatis 会自动把对应的值赋给 resultType 所指定对象的属性; 而当我们提供的返回类型是 resultMap 的时候,因为 Map 不能很好地表示领域模型,我们就需要通过进一步的定义把它转化为对应的实体对象。
当返回类型是 resultMap 时,也是非常有用的,这主要用在进行复杂联合查询上,当然在进行简单查询时是没有什么必要的,使用 resultType 足以。
说明:
1、Mybatis 是对返回的结果的每一行做映射的,因此在指定 resultType 或者 resultMap 返回类型时应特别注意是一行的类型而不是所有。
2、MyBatis 中在查询进行 select 映射的时候,返回类型可以用 resultType,也可以用 resultMap,resultType 是直接表示返回类型的,而 resultMap 则是对外部 resultMap 的引用,在 MyBatis 的 select 元素中,resultType 和 resultMap 本质上是一样的,都是 Map 数据结构。但需要明确一点: resultType 属性和 resultMap 属性绝对不能同时存在,只能二者选 其一使用。
3、在 MyBatis 中,使用 resultMap 能够进行自动映射匹配的前提是字段名和属性名需要一致,在默认映射级别(PARTIAL)情况下,若一致,即使没有做属性名和字段名的匹配,也可以在后台获取到未匹配过的属性值;若不一致,且在 resultMap 里没有做映射,那么就无法在后台获取并输出。
案例解析:根据用户名和用户角色 id 查询出用户表中用户信息,要求用户角色要显示角色名称而不是角色 id。
方式 1 :使用 resultType 做自动映射 (了解即可)
注意,MyBatis 中使用 resultType 做自动映射,一定要注意:字段名和 POJO 的属性名必须一致。若不一致,则需要给字段起别名,保证别名与属性名一致。
复制代码
(1)修改实体类 POJO:User.java,增加 userRoleName 属性,添加对应的 get 和 set 方法。
private String userRoleName; //用户角色名称
public String getUserRoleName() {
return userRoleName;
}
public void setUserRoleName(String userRoleName) {
this.userRoleName = userRoleName;
}
(2)UserMapper.java 接口中编写查询用户列表的 getUserList()方法。
/**
* 根据用户名称(模糊查询)和用户角色查询用户列表(要求用户角色要显示角色名称而不是角色 id)
* @param userName 用户名称
* @param userRole 用户角色
* @return
*/
public List getUserList(@Param(“uName”)String userName,@Param(“uRole”)int userRole);
(3)UserMapper.xml 中,编写查询用户列表的 SQL 语句,对表(mbms_user)和角色表(mbms_role)进行连表查询,使用 resultType 做自动映射。
<select id="getUserList" resultType="user">
SELECT u.*,r.roleName AS userRoleName FROM `smbms_user` u,`smbms_role` r
WHERE u.`userRole`=r.`id`
AND userRole=#{uRole}
AND userName LIKE CONCAT('%',#{uName},'%')
</select>
说明:使用 resultType 做自动映射,要求数据库字段名必须和 POJO 属性名一致。因此要给数据库字段取别名,别名为 userRoleName 。
(4)单元测试类
@Test //测试根据用户名称(模糊查询)和用户角色查询用户列表(要求用户角色要显示角色名称而不是角色 id)
public void testGetUserList(){
List userList=new ArrayList();
String userName=“赵”;
int userRole=2;
userList=session.getMapper(UserMapper.class).getUserList(userName, userRole);
for (User user : userList) {
System.out.println(user);
}
}
说明:此种方法必须给 r.roleName 取别名为 userRoleName 。
复制代码
方式 2 :使用 resultMap 来自定义映射结果(推荐使用)
通过 resultMap 来自定义映射结果。 使用 resultMap 做自定义结果映射,字段名可以不一致,并且还可以指定要显示的列,比较灵活,应用也广泛(推荐使用)
复制代码
(1)修改实体类 POJO:User.java,增加 userRoleName 属性,添加对应的 get 和 set 方法。
private String userRoleName; //用户角色名称
public String getUserRoleName() {
return userRoleName;
}
public void setUserRoleName(String userRoleName) {
this.userRoleName = userRoleName;
}
(2)UserMapper.java 接口中编写查询用户列表的 getUserList()方法。
/**
* 根据用户名称(模糊查询)和用户角色查询用户列表(要求用户角色要显示角色名称而不是角色 id)
* @param userName 用户名称
* @param userRole 用户角色
* @return
*/
public List getUserList(@Param(“uName”)String userName,@Param(“uRole”)int userRole);
(3)UserMapper.xml 中,编写查询用户列表的 SQL 语句,对表(mbms_user)和角色表(mbms_role)进行连表查询,使用 resultMap 做自定义结果映射。
<select id="getUserList" resultMap="userList">
SELECT u.*,r.roleName FROM
`smbms_user` u,`smbms_role` r
WHERE u.`userRole`=r.`id`
AND userRole=#{uRole}
AND userName LIKE CONCAT('%',#{uName},'%')
</select>
<resultMap type="user" id="userList">
<result property="id" column="id" />
<result property="userCode" column="userCode" />
<result property="userName" column="userName" />
<result property="phone" column="phone" />
<result property="birthday" column="birthday" />
<result property="gender" column="gender" />
<result property="userRole" column="userRole" />
<result property="userRoleName" column="roleName" />
</resultMap>
(4)单元测试类
@Test //测试根据用户名称(模糊查询)和用户角色查询用户列表(要求用户角色要显示角色名称而不是角色 id)
public void testGetUserList(){
List userList=new ArrayList();
String userName=“赵”;
int userRole=2;
userList=session.getMapper(UserMapper.class).getUserList(userName, userRole);
for (User user : userList) {
System.out.println(user);
}
}
说明:resultMap 做自定义结果映射,与 MyBatis 的自动映射级别(autoMappingBehavior)有关。
复制代码
注意点
在 MyBatis 中,使用 resultMap 能够进行自动映射匹配的前提是字段名和属性名需要一致,在默认映射级别(PARTIAL)情况下,若一致,即使没有做属性名和字段名的匹配,也可以在后台获取到未匹配过的属性值;若不一致,且在 resultMap 里没有做映射,那么久无法在后台获取并输出。
MyBatis 的自动映射级别
FULL:自动匹配所有。
PARTIAL(默认):自动匹配所有属性,有内部嵌套(association,collection)的除外。
NONE:禁止自动匹配。
MyBatis 的自动映射级别,需要在 mybatis-config.xml 的 settings 中设置,代码如下: