resultMap结果映射集详解


resultmap是mybatis中最复杂的元素之一,它描述如何从结果集中加载对象,主要作用是定义映射规则、级联的更新、定制类型转化器。

resultmap构成元素

元素 子元素 作用
constructor idArg 、arg 用于配置构造器方法
id 将结果集标记为id,以方便全局调用
result 配置POJO到数据库列名映射关系
association 级联使用 代表一对一关系
collection 级联使用 代表一对多关系
discriminator 级联使用 鉴别器 根据实际选择实例,可以通过特定条件确定结果集

1.id和result元素

以User类为例:

class User{private int userId;private String name;public User(long userId,String name){this.userId = userId;this.name = name;}
}

id、result是最简单的映射,id为主键映射;result其他基本数据库表字段到实体类属性的映射。resultmap的xml如下:

<resultMap type="User" id="userMap">  <id  property="UserId" column="user_id" javaType="int" jdbcType="int"/>  <result property="name" column="name" javaType="String" jdbcType="VARCHAR"/>
</resultMap>

id、result语句属性配置细节:

属性 描述
property 需要映射到JavaBean 的属性名称。
column 数据表的列名或者标签别名。
javaType 一个完整的类名,或者是一个类型别名。如果你匹配的是一个JavaBean,那MyBatis 通常会自行检测到。然后,如果你是要映射到一个HashMap,那你需要指定javaType 要达到的目的。
jdbcType 数据表支持的类型列表。这个属性只在insert,update 或delete 的时候针对允许空的列有用。JDBC 需要这项,但MyBatis 不需要。如果你是直接针对JDBC 编码,且有允许空的列,而你要指定这项。
typeHandler 使用这个属性可以覆写类型处理器。这项值可以是一个完整的类名,也可以是一个类型别名。

2. CONSTRUCTOR 构造器

在resultMap中,通常使用id、result子元素把Java实体类的属性映射到数据库表的字段上。但是如果在遇到JavaBean没有无参构造函数时,我还需要使用构造器元素实现一个JavaBean的实例化和数据注入。
再以User为例,那么对应的resultmap就需要添加构造器:

<constructor><idArg column="user_id" javaType="long"/><arg column="name" javaType="String"/>
</constructor>

定义java实体类的属性映射到数据库表的字段上。我们也可以使用实体类的构造方法来实现值的映射,这是通过构造方法参数的书写的顺序来进行赋值的。
这样MyBatis就知道需要用这个构造方法构造了。

3.结果集处理方法

1. 使用map储存结果集

一般情况下,所有select语句都可以使用map储存,但是使用map就意味着可读性的下井,所以这不是推荐的方式。

<select id="findUserById" parameterType="long" resultType="map">select user_id ,name form user where user_id=#{userId}
</select>
2. 使用POJO储存结果集(推荐

一般我们都使用POJO储存查询结果。我们可以使用select自动映射,还可以使用select语句中的resultMap属性配置映射集合,不过需要提前定义resultMap。
那我们就可以将之前的select语句修改:

<select id="findUserById" parameterType="long" resultMap="userMap">select user_id ,name form user where user_id=#{userId}
</select>

4.级联

在数据库中包含着一对多、一对一的关系。比如说一个人和他的身份证就是一对一的关系,但是他和他的银行卡就是一对多的关系。我们的生活中存在着很多这样的场景。我们也希望在获取这个人的信息的同时也可以把他的身份证信息一同查出,这样的情况我们就要使用级联。在级联中存在3种对应关系。
- 一对一的关系
- 一对多的关系
- 多对多的关系(这种情况由于比较复杂,我们通常会使用双向一对多的关系来降低复杂度)

1.association 一对一级联

我们继续使用User类,同时为其增加一个Card类,人和他的身份证就行成了一对一的关系。我们再创建一个Card类。

@Data
@Alias("card")
public class Card {private Long id;private Long userId;private String name;private String address;
}

这是需要在User中添加属性Card,这样就形成了一对一的级联。

@Data
@Alias("user")
public class User {
private Long id;
private String username;
private String password;
private String email;
private Card card;

}
这里使用了Lombok的Data注解省去了get和set等方法。使用Alias注解添加其别名。

Lombok 是一种 Java™ 实用工具,可用来帮助开发人员消除 Java 的冗长,尤其是对于简单的 Java 对象(POJO)。它通过注解实现这一目的。以后会添加其使用方法的文章。

这时需要CardMapper提供findCardByUserId(Long userId)方法,定义其映射器如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.changzhen.mybatis.mapper.CardMapper"><resultMap id="cardMap" type="card"><id property="id" column="id"></id><result property="userId" column="user_id"/><result property="name" column="name"/><result property="address" column="address"/></resultMap><select id="findCardByUserId" parameterType="long" resultMap="cardMap">SELECT id, user_id, name, address FROM card WHERE user_id = #{userId}</select>
</mapper>

有了CardMapper,我们将可以在UserMaper中使用 findCardByUserId 进行级联

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.changzhen.mybatis.mapper.UserMapper">
<select id="getUser" resultMap="userMap" parameterType="long">SELECT id,username,password,email FROM USER WHERE id=#{id}
</select>
<resultMap id="userMap" type="user"><id property="id" column="id"/><result property="password" column="password"/><result property="email" column="email"/><association property="card" column="id" select="com.changzhen.mybatis.mapper.CardMapper.findCardByUserId"/>
</resultMap>

注意在getUser的时候,一定要将数据库的id获取到,开始我以为在传入id的时候就已经把id传入findCardByUserId的userId了,结果怎么都获取不到Card。后来发现原来是根据返回的id进而级联查询。

通过关联处理,其中select元素指定的sql查询,而column则是指定传递给select的参数,是user对象id。当取出User的时候,MyBatis就知道下面的sql取出我们需要的级联信息。

 <association property="card" column="id" select="com.changzhen.mybatis.mapper.CardMapper.findCardByUserId"/>

其中参数是User的值,通过column配置,如果是多个参数则使用逗号隔开。

通过测试

可以看出执行了两条sql分别查询了User和Card。

2.collection 一对多级联

这一对多的级联,一个身份证可以办理多张银行卡。每个用户对应一个身份证,每个身份证对应多个银行卡。所以这两个级联,分别使用association和collection完成。
- 首先,创建BankCard类,为Card增加bankCardList属性

@Alias("bankCard")
@Data
public class BankCard {private Long id;private Long userId;private String bankName;private int type;
}@Data
@Alias("card")
public class Card {private Long id;private Long userId;private String name;private String address;private List<BankCard> bankCards;
}
  • 创建BankCardMapper

    @Mapper
    public interface BankCardMapper {
    public List findCreditCardsByUserId(Long userId);
    }

  • xml最简单的映射器

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.changzhen.mybatis.mapper.CreditCardMapper"><select id="findCreditCardsByUserId" parameterType="long" resultType="creditCard">SELECT id, user_id, bank_name, type FROM bank_card WHERE user_id = #{userId}</select></mapper>
  • 最后在Card映射器中添加collection,一对多级联。
 <mapper namespace="com.changzhen.mybatis.mapper.CardMapper"><resultMap id="cardMap" type="card"><id property="id" column="id"></id><result property="userId" column="user_id"/><result property="name" column="name"/><result property="address" column="address"/><collection property="creditCards" column="id" select="com.changzhen.mybatis.mapper.BankCardMapper.findBankCardsByUserId"/></resultMap><select id="findCardByUserId" parameterType="long" resultMap="cardMap">SELECT id, user_id, name, address FROM card WHERE user_id = #{userId}</select>
</mapper>

-通过测试

可以看出共执行了三条sql语句。

3.discriminator 鉴别器级联

鉴别器级联是在不公情况下使用不同的POJO。例如,在本例中我们每个人都有好多银行卡,但是银行卡的种类却不同,比如有借记卡(DebitCard)和信用卡(CreditCard),我们需要按需来创建不同的POJO。这时我们就需要在BankCard中添加types属性进行判断,确定使用哪个POJO。
接下来需要创建DebitCard和CreditCard两个继承BankCard的子类

@Data
public class CreditCard extends BankCard {
/*** 消费额度*/private String creditLine;
}
@Data
public class DebitCard extends BankCard {/*** 存款金额*/private String deposit;
}

通过BankCard中types的属性判断使用哪种银行卡,例如types等于1为借记卡,等于2为信用卡。接下来需要修改bankCard.xml,添加discriminator鉴别器,它相当于java中的switch语句。

bankCard.xml修改为如下:

<mapper namespace="com.changzhen.mybatis.mapper.BankCardMapper"><resultMap id="bankCardMapper" type="bankCard"><id property="id" column="id"/><result property="userId" column="user_id"/><result property="bankName" column="bank_name"/><result property="types" column="types"/><discriminator javaType="int" column="types"><case value="1" resultMap="debitCardMapper"></case><case value="2" resultMap="creditCardMapper"></case></discriminator>
</resultMap><select id="findBankCardsByUserId" parameterType="long" resultMap="bankCardMapper">SELECT id, user_id, bank_name, types FROM bank_card WHERE user_id = #{userId}
</select><resultMap id="debitCardMapper" type="debitCard" extends="bankCardMapper"/><resultMap id="creditCardMapper" type="creditCard" extends="bankCardMapper"/>

其中

    <discriminator javaType="int" column="types"><case value="1" resultMap="debitCardMapper"></case><case value="2" resultMap="creditCardMapper"></case></discriminator>

首先定义了 discriminator ,它对应的column为types,java类型(jdbcType)为int。
case配置了不同的resultMap,如value=1时,引入debitCardMapper,value=2时
,引入creditCardMapper他们都扩展了bankCardMapper。
就像继承关系一样,resultMap也可以继承,加入自己的属性。借记卡添加deposit属性,信用卡添加creditLine属性。
-通过运行测试

由图可以看出,返回的数据已经根据types使用了不同的POJO。

后续会讨论性能问题、延迟加载和其他级联。

[MyBatis]-resultMap结果映射集详解相关推荐

  1. Mybatis中Mapper映射文件详解(默认值)

    Mapper映射文件是一个xml格式文件,必须遵循相应的dtd文件规范,如ibatis-3-mapper.dtd.我们先大体上看看支持哪些配置?如下所示,从Eclipse里截了个屏: 从上图可以看出, ...

  2. mybatis多对一映射association详解

    简单映射(一对一) 多对一映射 方式1:按照查询嵌套处理 方式2:按照结果嵌套处理 简单映射(一对一) mybatis结果集映射ResultMap 多对一映射 我们有2个类,一个班级类ClassRoo ...

  3. Mybatis复习笔记3:映射文件详解

    映射文件详解 参数处理(#和$的区别) #{}:可以获取map中的值或者实体对象属性的值: ${}:可以获取map中的值或者实体对象属性的值: select * from person where i ...

  4. 【java学习之路】(java框架)004.Mybatis SQL映射文件详解

    02Mybatis SQL映射文件详解 ​ 在之前我们学习了mybatis的全局配置文件,下面我们开始学习mybatis的映射文件,在映射文件中,可以编写以下的顶级元素标签: cache – 该命名空 ...

  5. mysql在xml中jdbctype,MyBatis中的JdbcType映射使用详解

    Java项目涉及到数据库交互,以往常用的是JDBC,现在则有Hibernate.Mybatis等这些持久化支持. 项目中用到了MyBatis,和JDBC最显著的区别,就是SQL语句配置化,通过xml文 ...

  6. Mybaits(3),映射文件详解

    Mybaits(3),映射文件详解 MyBatis 的真正强大在于它的语句映射,这是它的魔力所在.由于它的异常强大,映射器的 XML 文件就显得相对简单.如果拿它跟具有相同功能的 JDBC 代码进行对 ...

  7. resultMap和resultType区别详解

    resultMap和resultType区别详解 resultmap与resulttype的区别为:对象不同.描述不同.类型适用不同 一.对象不同 1.resultmap:resultMap如果查询出 ...

  8. resultmap的写法_mybatis的mapper.xml中resultMap标签的使用详解

    1.前言 最近博主在做一个ssm框架的共享汽车管理系统,其中,数据库字段设计的有下划线方式,a_username,然后在写mapper.xml里面的sql语句的时候,一直出现查询语句查询的值为null ...

  9. mysql resulttype map_Mybatis中的resultType和resultMap查询操作实例详解

    resultType和resultMap只能有一个成立,resultType是直接表示返回类型的,而resultMap则是对外部ResultMap的引用,resultMap解决复杂查询是的映射问题.比 ...

最新文章

  1. whereis php,Linux命令教程之比较搜索命令whereis与which的区别
  2. MySQL自动化平台那些事-分秒必争
  3. python入门基础代码图-Python入门基础学习一
  4. 服务总线yali测试_满足吉利要求的车载总线测试服务
  5. 剑灵力士卡刀ahk_技术宅教你:召唤代码一键卡刀详细教程帖
  6. python flask源码解析_浅谈flask源码之请求过程
  7. mysql远程连接权限grant all privileges on *.* to ‘root‘@‘%‘ identified by ‘123456‘ with grant option语句报错
  8. java treeset比较,java中TreeSet的两种排序比较的方式
  9. 为高考学子加油,Java快速开发平台,JEECG 3.7.6高考性能增强版本发布
  10. 【word基础知识】如何将论文中的引文标签和参考文献编号自动关联
  11. python女朋友_教你用Python感知女朋友的情绪变化!
  12. 我的面试标准:能干活、基础要好、有潜力!
  13. 如何让U盘对病毒免疫
  14. MISRA C-2012规则中文版
  15. Android设置屏幕亮度的两种方式
  16. 操作系统应用阶层现状,对操作系统的认识
  17. vue 百度地图 3d地图
  18. java 调用felix_寻找在动态加载Jar文件中使用Apache Felix并在Java中在运行时实例化类的基本示例...
  19. 豆粕5连跌四月季节性偏弱,铁矿石认购翻倍,甲醇05-09季节性反套2022.3.30
  20. 如何选择日志审计系统

热门文章

  1. Python金融数据分析可能用到的55个数据集,财富密码可能埋藏于此
  2. 陪诊小程序开发|陪诊护理系统|陪护软件开发
  3. 试发布《燕掠天空视频点播系统》
  4. Jquery 15 天教程
  5. 《软件工程之美》—— 理解软件工程
  6. java 数组去重_java利用set给数组去重
  7. python爬虫-淘宝商品密码(图文教程附源码)
  8. 诺禾;诺禾阐述java高并发
  9. NOR Flash的学习
  10. RocketMQ 中Topic、Tag、GroupName基本概念介绍