大神带你重新认识Mybatis中强大的resultMap

前言
在Mybatis中,有一个强大的功能元素resultMap。当我们希望将JDBC ResultSets中的数据,转化为合理的Java对象时,你就能感受到它的非凡之处。正如其官方所述的那样:

resultMap元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作。实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份 resultMap 能够代替实现同等功能的长达数千行的代码。ResultMap 的设计思想是,对于简单的语句根本不需要配置显式的结果映射,而对于复杂一点的语句只需要描述它们的关系就行了。

一、字段映射

在Mybatis中,最简单的结果映射方式,就是通过类型别名typeAliases来处理。

如果要这样做,那么第一步需要配置实体类包的路径:

mybatis.type-aliases-package=com.xxx.entity

该路径下的所有类,就会被注册到TYPE_ALIASES容器。我们在指定返回值类型的时候,就直接用别名即可。

比如,我们有一个User类:

如果数据库中表的字段与User类的属性名称一致,我们就可以使用resultType来返回。


当然,这是理想状态下,属性和字段名都完全一致的情况。但事实上,不一致的情况是有的,这时候我们的resultMap就要登场了。

如果User类保持不变,但SQL语句发生了变化,将id改成了uid。


那么,在结果集中,我们将会丢失id数据。这时候我们就可以定义一个resultMap,来映射不一样的字段。

<resultMap id="getUserByIdMap" type="User">
    <result property="id" column="uid"></result>
</resultMap>

然后,我们把上面的select语句中的resultType修改为resultMap="getUserByIdMap"。

这里面column对应的是数据库的列名或别名;property对应的是结果集的字段或属性。

这就是resultMap最简单,也最基础的用法:字段映射。

下面,我们看看其他几种标签都是怎么应用的。


二、构造方法
如果你希望将结果注入构造方法里,就可以用到constructor元素。

比如,我们的User类增加了一个构造方法:

public User(String id, String name) {
this.id = id+"--------";
this.username = name+"--------";
}
我们需要在resultMap中定义constructor元素:


其中,column代表数据库字段名称或者别名;name则是构造方法中的参数名称;javaType指定了参数的类型。

如你所想,这样指定构造方法后,我们结果集中的id和username属性都会发生变化。

{
 "id": "1001--------",
 "username": "sunning",
 "password": "123456",
 "address": "北京市海淀区",
 "email": 923330117qq.com"
}

三、关联

在实际的业务中,我们的用户一般都会有一个角色。那么在User类里面一般也是以一个实体类来表示。

@Data
public class User {
 //省略用户属性...

 //角色信息
 private Role role;
}

我们在查询用户的时候,如果也希望看到它的角色信息,我们会这样来写查询语句:


如上,就要查询单个用户以及用户的角色信息。不过在这里,我们不能用resultType=User来返回。

毕竟,User类中只有一个Role对象,并没有role_id和role_name字段属性。

所以,我们要使用association来关联它们。


最后我们就可以将角色信息一块显示出来:

事实上,如果你确定关联信息是一对一的情况,有个更简便的方法可以替代association,我们在本文的第五部分-自动填充关联对象再看它是怎么实现的。

四、集合
1、集合的嵌套结果映射

上面我们看到一个用户后羿,它的角色是射手;但大部分时候,我们每个人都不可能只拥有一种角色。所以,我们需要将User类中的角色属性的类型改成List。

@Data
public class User {
 //省略用户属性...

 //角色信息
 private List<Role> roles;
}

现在就变成了一个用户对应多个角色,所以就不是简单的association。

因为association处理的是有一个类型的关联;而我们这里是有多个类型的关联,所以就需要用到collection属性。

我们整体的resultMap会变成下面这样:


这样的话,即便你有多个角色也可以被正确显示:


2、集合的嵌套 Select 查询

在大部分业务系统中,我们都会有一个菜单的表,比如像下面这样,一张Menu表:


这里我们给菜单分为两级。我们给前端返回菜单的时候,也是需要分级的,不可能将这7条数据平级展示。那么,在这里我们的Menu实体类如下:

@Data
public class Menu {
 private String id;
 private String name;
 private String url;
 private String parent_id;
 private List<Menu> childMenu;
}

一级菜单,包含一个二级菜单的列表,这里用childMenu来表示。

SQL语句中,如果没有parent_id字段属性,我们就先查所有的一级菜单:


这个查询语句,在不传输任何参数的情况下,我们会得到两条一级菜单的数据。

那么在只调用此方法一次的情况下,怎么把所有的菜单信息查询出来,并按层级展示呢?

我们来看menusMap的定义:


重点来看collection元素:

property="childMenu" 对应的是菜单中的子级菜单列表;

ofType="Menu" 对应返回数据的类型;

select="getMenus" 指定了SELECT语句的id;

column="{parent_id=id}" 则是参数的表达式。

这个collection整体的含义可以这样理解:

通过getMenus这个SELECT语句来获取一级菜单中的childMenu属性结果;在上面的SELECT语句中,需要传递一个parent_id参数;这个参数的值就是一级菜单中的id。

通过这种方式,我们就可以得到已分级的所有菜单信息。


五、自动填充关联对象
我们知道,在Mybatis解析返回值的时候。

第一步是获取返回值类型,拿到Class对象,然后获取构造器,设置可访问并返回实例,然后又把它包装成MetaObject对象。

从数据库rs中拿到结果之后,会调用MetaObject.setValue(String name, Object value) 来填充对象。

在这过程中,有趣的是,它会以.来分隔这个name属性。

如果name属性中包含.符号,就找到.符号之前的属性名称,把它当做一个实体对象来处理。

可能笔者在这里描述的不够直观,我们还是来看例子。

在本文第三部分中,我们有一个用户对应一个角色的例子。

其中,User类定义如下:

@Data
public class User {
 //省略用户属性...

 //角色信息
 private Role role;
}

在这里,我们无需定义resultMap,直接返回resultType=User即可。不过需要把role信息的别名修改一下,重点是.符号

这样,在Mybatis解析到role.id属性的时候,以.符号分隔之后发现,role别名对应的是Role对象,则会先初始化Role对象,并将值赋予id属性。

相关代码如图:

原文地址:https://blog.51cto.com/14207399/2413443

时间: 2024-11-07 01:43:58

大神带你重新认识Mybatis中强大的resultMap的相关文章

Django 大神带你飞系列~走进Django

Django 大神带你飞系列~走进Django Django开端 1.0 django 开端 1.1 web应用的本质 1.2 HTTP协议 1.3 路由系统 1.4 Django的安装和启动 1.5 django的路由介绍 1.6 Django的模版介绍 1.7 Django的网页操作流程 1.8 Django的链接数据库操作 Django的路由系统 1.0 Django的路由系统 1.1 创建app 1.2 路由的分组 1.3 路由的分法 Django的orm模型 1.0 Django 的o

老猪带你玩转自定义控件三——sai大神带我实现ios 8 时间滚轮控件

ios 8 的时间滚轮控件实现了扁平化,带来很好用户体验,android没有现成控件,小弟不才,数学与算法知识不过关,顾十分苦恼,幸好在github上找到sai大神实现代码,甚为欣喜,顾把学习这个控件点滴记录下来,分享给大家.项目原地址https://github.com/saiwu-bigkoo/Android-PickerView. ios 8 滚轮的效果: 而sai大神控件的效果: 哎,妈呀是不是效果95%相识啊. 好了,废话少说,谈谈我从这个控件中收获的心得. 首先,我们要高瞻远瞩看一下

mybatis中resultType和resultMap的区别

MyBatis中在查询进行select映射的时候,返回类型可以用resultType,也可以用resultMapresultType是直接表示返回类型的,而resultMap则是对外部ResultMap的引用但是resultType跟resultMap不能同时存在.在MyBatis进行查询映射的时候,其实查询出来的每一个属性都是放在一个对应的Map里面的,其中键是属性名,值则是其对应的值.当提供的返回类型属性是resultType的时候,MyBatis会将Map里面的键值对取出赋给resultT

[转]MyBatis中resultType与resultMap区别

MyBatis中关于resultType和resultMap的具体区别如下: MyBatis中在查询进行select映射的时候,返回类型可以用resultType,也可以用resultMap.resultType是直接表示返回类型的(对应着我们的model对象中的实体):resultMap则是对外部ResultMap的引用(提前定义了db和model之间的隐射key-->value关系):resultType跟resultMap不能同时存在. 在MyBatis进行查询映射时,其实查询出来的每一个

关于mybatis中mapper文件resultMap中collection的使用

collection的使用有两种resultMap和select,必须手动指定一种 1. 实体类: 1 package com.mrlu.mybatis.domain; 2 3 import java.util.List; 4 5 /** 6 * Created by stefan on 15-12-31. 7 */ 8 public class User { 9 private Integer id; 10 private String name; 11 private List<Accoun

css3动画transform在ie内核动画结束后子元素a标签不能点击(本人未解决,求大神带飞)

问题描述: css3的动画 animation属性,如果动画里面需要动画的元素是transform,那么动画的这个元素的子元素a标签就不能 点击跳转,也不能运行点击事件,就好像个a标签被透明的东西挡住了一样,目前只是发现这个问题在ie内核的浏览器上面,比如 360浏览器,ie11(考虑到测试css3动画的,没有测试ie789 10.).而在火狐,谷歌正常. 百度了一大堆,都没有找到好的解决办法,比较接近的一个说法是,transform属性改变了元素的层级,也就是z-index属性,不过在这里a标

2018年最新-JAVA大神带你做年薪过50万的架构师

一.作为企业架构师,我们为什么需要构建数据结构? 数据结构主要有以下内容: 1)数据标准不一致 2)数据模型管理混乱 3)深入的性能的问题无法解决 4)SQL语句编写水平不高导致出现严重性能问题 5)开发人员对执行计划收悉 6)上线前缺乏审计 7)相对复杂的数据处理能力欠缺 8)数据质量差需要执行数据质量管理 数据是客户的财富,虽然对于我们开发人员一文不值,在客户那里就是无价之宝,保障数据的完成性,安全性,可靠性, 二.作为一名数据架构师所掌握职责和技术 创建数据管理系统进行整合,集中,保护和维

西南seo大神带你走在时代前沿,方能把我机遇迎接挑战,

走在时代前沿,带领家庭生态农业农庄发展是否怀恋儿时那石磨磨出的面粉,是否对农村的自然风光,清新的空气,叮咚的泉水意犹未尽,是否想念你孩童时的烧洋芋,或是在山上生上柴火掰几个玉米烤熟时的味道,是否很想再追忆一下年轻时嬉戏玩耍的乐趣,我也很怀恋,可是我也很绝望,真的无法,看来只能回家去扎西红了.在互联网+时代发展生态农业和生态农业庄园,走家庭农庄,乡村旅游这条路真的可行吗?不要怀疑,我们走在时代的前沿,相信我,在五年前我就知道了农村电商势必所趋,果然,在2016年,国家对农村电商立项且大力扶持,每个

腾讯课堂:腾讯大神带你进阶性能测试

1,性能测试最有用的图:虚拟用户,吞吐量,相应时间,资源利用率的关系图. 2,性能测试工具: jmeter , loadrunner ,tcpcopy , gatling,自己写. 3,微信红包的实例: 微信红包的功能就很复杂:发红包,在群内或是针对个人,发多少个,抢红包请求等. 验证数据的正确性,直接通过脚本很难验证,所以再跑完脚本之后写程序验证正确性,付款正确,收款正确,计算正确等等. 4,面试的时候,一般会问你在实际操作中遇到哪些问题,怎么解决的,复杂的测试实例是什么. 原文地址:http