MyBatis——详解ResultMap结果映射

本文详细解读了MyBatis ResultMap在处理Java对象映射中的关键元素,包括关联(association)、collection级联、嵌套查询与结果映射,以及鉴别器的使用。适合后端开发者深入了解数据库到对象的映射策略。
摘要由CSDN通过智能技术生成

📢📢📢📣📣📣

哈喽!大家好,我是【一心同学】,一位上进心十足的【Java领域博主】!😜😜😜

✨【一心同学】的写作风格:喜欢用【通俗易懂】的文笔去讲解每一个知识点,而不喜欢用【高大上】的官方陈述。

✨【一心同学】博客的领域是【面向后端技术】的学习,未来会持续更新更多的【后端技术】以及【学习心得】。

✨如果有对【后端技术】感兴趣的【小可爱】,欢迎关注一心同学】💞💞💞

❤️❤️❤️感谢各位大可爱小可爱!❤️❤️❤️ 


一心同学将在本章为大家讲解一个MyBatis最强大的元素---ResultMap,让我们一起来欣赏它迷人的地方。

目录

一、ResultMap介绍

二、id & result

三、CONSTRUCTOR 构造方法

四、关联association

4.1关联的嵌套 Select 查询

4.2关联的嵌套结果映射

4.2.1结果映射作为子元素嵌套在内

4.2.2.外部结果映射元素来映射关联

五、collection 一对多级联

5.1集合的嵌套 Select 查询

5.2集合的嵌套结果映射

六、鉴别器

总结

结语


一、ResultMap介绍

resultMap 元素是 MyBatis 中最重要最强大的元素,同时也是MyBatis最复杂的元素之一,它是一种数据库映射模式描述如何从结果集中加载对象,主要作用是定义映射规则、级联的更新、定制类型转化器。

功能解决数据库到对象的映射问题

在此我们先来了解一下ResultMap的组成元素:

ResultMap的组成元素:

  • constructor - 实例化类时,注入结果到构造方法中
            idArg - ID 参数; 将结果集标记为ID,以方便全局调用
             arg -注入构造器的结果集
  • id – 结果集ID,将结果集标记为ID,以方便全局调用
  • result – 注入到字段或 JavaBean 属性的普通结果
  • association – 一个关联;一对一的关系,即将结果包装成这种类型
    嵌套结果映射 – associations能引用自身,或者从其它地方引用
  • collection – 一个复杂类型的集合,一对多的关系
    嵌套结果映射 – collections能引用自身,或者从其它地方引用
  • discriminator – 使用结果值来决定使用哪个 resultMap
  • case – 基于某些值的结果映射
    嵌套结果映射 – case 也是一个结果映射,因此具有相同的结构和元素;或者引用其它的结果映射

接下来就开始一心同学的讲解。

二、id & result

实体类:

public class Blog {
    private int id;
    private String name;
    private String password;//这里的password与数据库的pwd不一致
    //set,get,无参,有参
}

接口:

public Blog selectBlogById(int id);

映射文件:

<resultMap id="blogResult" type="Blog">
    <id column="id" property="id"/><!--主键映射-->
    <result column="pwd" property="password"/><!--数据库表字段到实体类属性的映射-->
    <result column="name" property="name"/>
</resultMap>

<select id="selectBlogById" parameterType="int" resultMap="blogResult">
select * from blog where id=#{id}
</select>

一心同学先用通俗易懂的话来讲一下各个属性。
idresult的属性:

id:一般作为主键映射,方便全局调用。
result:数据库表字段到实体类属性的映射。
column:数据库字段名
property:实体属性名
javaType:指Java类该属性的类型,可以是完全限定名,或一个类型别名(例如:int的类型别名就是_int,Integer的类型别名就是int)如果是映射到一个 JavaBean,MyBatis 通常可以自动推断类型,即不需要我们写。

而对于各个属性详细解释如下:

ResultMap 的属性列表
属性描述
id主键,当前命名空间中的一个唯一标识,用于标识一个结果映射。
type类的完全限定名, 或者一个类型别名
autoMapping如果设置这个属性,MyBatis 将会为本结果映射开启或者关闭自动映射。 这个属性会覆盖全局的属性 autoMappingBehavior。默认值:未设置(unset)。
 

而id和result的属性细节注意如下: 

Id 和 Result 的属性
属性描述
property需要映射到JavaBean 的属性名称。
column数据库中的列名,或者是列的别名。
javaType一个 Java 类的全限定名,或一个类型别名。 如果你映射到一个 JavaBean,MyBatis 通常可以自动推断类型。然而,如果你映射到的是 HashMap,那么你应该明确地指定 javaType 来保证行为与期望的相一致。
jdbcType数据表支持的类型列表。这个属性只在insert,update 或delete 的时候针对允许空的列有用。JDBC 需要这项,但MyBatis 不需要。如果你是直接针对JDBC 编码,且有允许空的列,而你要指定这项。
typeHandler这个属性可以覆盖默认的类型处理器。 这个属性值是一个类型处理器实现类的全限定名,或者是类型别名。

三、CONSTRUCTOR 构造方法

介绍:构造方法注入允许你在初始化时为类设置属性的值,而不用暴露出公有方法。

构造方法:

public Blog(@Param("id") int id, @Param("name") String name, @Param("password") String password) {
        this.id = id;
        this.name = name;
        this.password = password;
        }
 

映射文件: 

<resultMap id="constructResult" type="Blog">
    <constructor>
        <idArg column="id" javaType="_int" name="id"/>
        <arg column="name" javaType="String" name="name"/>
        <arg column="pwd" javaType="String" name="password"/>
    </constructor>
</resultMap>
<select id="selectBlogById" parameterType="int" resultMap="constructResult">
select * from blog where id=#{id}
</select>

讲解

idArg:一般是作为主键元素,方便全局调用。 javaType:指Java类该属性的类型,可以是完全限定名,或一个类型别名(例如:int的类型别名就是_int,Integer的类型别名就是int) name:指构造方法的参数名,需要对构造方法用@Param("指定名字")指定相应属性的名字,不然MyBatis不知道。

四、关联association

介绍一对一的关系,将结果包装成这种类型,例如:

一篇博客只有一个作者,但一个作者可以有多篇博客,那么就应该在博客这边关联作者,对博客而言,他只需认定一个作者即1对1。

Blog实体类:

public class Blog {
    private int id;
    private String name;
    private String pwd;
    private Author author;
    //set,get,无参,有参
}

Author实体类:

public class Author {
    private int author_id;
    private String author_name;
    private String author_pwd;
    //set,get,无参,有参
}

注意:现在有两个实体类了,意味着为了规范化,需要在resource目录下创建实体类相同的目录,将两个映射文件AuthorMapper.xml和BlogMapper.xml移到该目录下并记得去配置文件重新匹配路径,这是为了规范化,当然,你不这么做也可以,只是当项目大了之后就会非常难以维护。

配置文件配置路径:

<mappers>
    <mapper resource="com/yixin/dao/BlogMapper.xml"/>
    <mapper resource="com/yixin/dao/AuthorMapper.xml"/>
</mappers>

这是我的目录截图:

 

MyBatis 有两种不同的方式加载关联:

  • 嵌套 Select 查询:通过执行另外一个 SQL 映射语句来加载期望的复杂类型。
  • 嵌套结果映射:使用嵌套的结果映射来处理连接结果的重复子集。

4.1关联的嵌套 Select 查询

属性

select:用于加载复杂类型属性的映射语句的 ID,它会从 column 属性指定的列中检索数据,作为参数传递给目标 select 语句

AuthorMapper接口:

public interface AuthorMapper {
 public Author getAuthor(int author_id);
}

BlogMapper接口:

public interface BlogMapper {
 public Blog selectBlogById(int id);
}

映射文件:

AuthorMapper.xml

<mapper namespace="com.yixin.dao.AuthorMapper">

    <select id="getAuthor" resultType="Author">
        select * from author where author_id=#{id}<!--只有一个属性,id可以取任意值-->
    </select>
</mapper>
 

BlogMapper.xml 

<mapper namespace="com.yixin.dao.BlogMapper">
    
    <resultMap id="blogResultSelect" type="Blog">
        <id column="id" property="id"/>
        <result column="pwd" property="pwd"/>
        <result column="name" property="name"/>
        <!---以上三个属性由于跟数据库字段相同,故也可以不写,这里只是为了方便大家理解-->
        <association property="author" column="author_id" javaType="Author" select="com.yixin.dao.AuthorMapper.getAuthor"/>
    </resultMap>
    
    <select id="selectBlogById" parameterType="int" resultMap="blogResultSelect">
        select * from blog where id=#{id}
    </select>
    
</mapper>


讲解
property:实体的属性名
column:数据库的字段名
javaType:表示传给实体对象的类型是Author
select:将column拿到的author_id的值传进去,getAuthor根据传进来的id值拿到Author这个对象,并返回去。



注意:如果希望通过两个或多个参数确定Author的对象,则column的取值可以用","分割。
AuthorMapper.xml

<select id="getAuthorByIdAndName" resultType="Author">
 select * from author where author_id=#{id} and author_name=#{name}
</select>

BlogMapper.xml

<select id="selectBlogById" parameterType="int" resultMap="blogResultSelectByIdName">
    select * from blog where id=#{id}
</select>

<resultMap id="blogResultSelectByIdName" type="Blog">
<association property="author" column="{id=id,name=name}" javaType="Author" select="com.yixin.dao.AuthorMapper.getAuthorByIdAndName"/>
</resultMap>

讲解

通过column定义的id,name,然后用select将id和name传入getAuthorByIdAndName,进入返回Author.

4.2关联的嵌套结果映射

属性:

resultMap :结果映射的 ID,可以将此关联的嵌套结果集映射到一个合适的对象树中。

嵌套结果映射又分为两种

1.结果映射作为子元素嵌套在内

2.外部结果映射元素来映射关联

4.2.1结果映射作为子元素嵌套在内

 

接口方法: 

public Blog selectBlog();
 

映射文件: 

<select id="selectBlog" resultMap="blogResultMap">
    select a.*,b.* from blog b,author a
</select>
<resultMap id="blogResult" type="Blog">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="pwd" property="pwd"/>
<association property="author" javaType="Author" >
    <id column="author_id" property="author_id"/>
    <result column="author_name" property="author_name"/>
    <result column="author_pwd" property="author_pwd"/>
</association>
</resultMap>

讲解

查询出两个表的所有属性,然后利用这些属性在Blog里面进行分配,association则是用这些属性,生成一个Author对象

注意
 id 元素在嵌套结果映射中扮演着非常重要的角色。你应该总是指定一个或多个可以唯一标识结果的属性。 虽然,即使不指定这个属性,MyBatis 仍然可以工作,但是会产生严重的性能问题。 


4.2.2.外部结果映射元素来映射关联


这种方式的特点是子结果映射可重用
映射文件:

<resultMap id="blogResultMap" type="Blog">
    <id column="id" property="id"/>
    <result column="name" property="name"/>
    <result column="pwd" property="pwd"/>
    <association property="author" column="author_id" javaType="Author" resultMap="getAuthor"/>
</resultMap>

<resultMap id="getAuthor" type="Author">
<id column="author_id" property="author_id"/>
<result column="author_name" property="author_name"/>
<result column="author_pwd" property="author_pwd"/>
</resultMap>

讲解

查询出所有元素后,利用resultMap嵌套了另一个resultMap---getAuthor,getAuthor同样能拿到所有的属性字段,并生成一个Author对象返回。

五、collection 一对多级联

讲解:一个作者可以有多个博客,那么为了获取作者的全部博客,我们可以对实体类Author进行如下定义

public class Author {
    private int author_id;
    private String author_name;
    private String author_pwd;
    private List<Blog> blogs;
//get,set,有参构造,无参构造
}

对于这样的映射文件的实现方式,又分为两种

1.集合的嵌套 Select 查询

2.集合的嵌套结果映射

5.1集合的嵌套 Select 查询

接口:

public Author getAuthor(int author_id);

映射文件:

AuthorMapper.xml

<select id="getAuthor" resultMap="authorResult2">
    select a.*,b.* from blog b,author a where b.author_id=#{id}
</select>

<resultMap id="authorResult2" type="Author">
<id column="author_id" property="author_id"/>
<result column="author_name" property="author_name"/>
<result column="author_pwd" property="author_pwd"/>
<collection property="blogs" javaType="ArrayList" column="id" ofType="Blog"
            select="com.yixin.dao.BlogMapper.selectBlogById"/>
</resultMap>

BlogMapper.xml

<select id="selectBlogById" parameterType="int" resultMap="blogResultSelectByIdName">
    select * from blog where id=#{id}
</select>
<resultMap id="blogResultSelectByIdName" type="Blog">
<association property="author" column="{id=id,name=name}" javaType="Author" select="com.yixin.dao.AuthorMapper.getAuthorByIdAndName"/>
</resultMap>

讲解

column拿到字段id,传递给select,然后通过返回一个Blog组成集合blogs。

Collection:

  • JavaTypeofType都是用来指定对象类型的
          JavaType是用来指定pojo中属性的类型
          ofType指定的是映射到list集合属性中pojo的类型

5.2集合的嵌套结果映射

映射文件:

<select id="getAuthor" resultMap="authorResult2">
    select a.*,b.* from blog b,author a where b.author_id=#{id}
</select>

<resultMap id="authorResult" type="Author">

<id column="author_id" property="author_id"/>

<result column="author_name" property="author_name"/>

<result column="author_pwd" property="author_pwd"/>

<collection property="blogs" ofType="Blog">
    <id column="id" property="id"/>
    <result column="name" property="name"/>
    <result column="pwd" property="pwd"/>
</collection>

</resultMap>
 

讲解

ofType:指定的是映射到list集合属性中pojo的类型

property:该集合的属性名

六、鉴别器

介绍:

有时候,一个数据库查询可能会返回多个不同的结果集,鉴别器元素就是被设计来应对这种情况的,另外也能处理其它情况,例如类的继承层次结构。 鉴别器的概念很好理解——它很像 Java 语言中的 switch 语句。

理解:一个作者的博客可以有多种类型,可以是技术类型的,娱乐类型的,工作类型等等,而这些类型的博客都是继承了Blog这个类,当我们要去找出某种类型的博客时(type_blog),并将其加载出来,这时候就需要用到鉴别器了。

class TechnologyBlog extends Blog{
 private String study;
}
class PlayBlog extends Blog{
 private String game;
}

通过type_blog这个属性判定要加载哪个博客。

对于Author这个表的属性如下:

int id,

String name,

String pwd,

int type_blog,

study,

game.

映射文件:

<resultMap id="BlogResult" type="Blog">
    <id property="id" column="id" />
    <result property="name" column="name"/>
    <result property="pwd" column="pwd"/>

    <discriminator javaType="int" column="type_blog">
        <case value="1" resultMap="technologyResult"/>
        <case value="2" resultMap="playResult"/>
    </discriminator>
</resultMap>

<resultMap id="technologyResult" type="TechnologyBlog" extends="BlogResult">

<result property="study" column="study" />

</resultMap>

<resultMap id="playResult" type="PlayBlog" extends="BlogResult">

<result property="game" column="game" />

</resultMap>

讲解

MyBatis 会从结果集中得到每条记录,然后比较它的 best_blog 值。 如果它匹配任意一个鉴别器的 case,就会使用这个 case 指定的结果映射。就像继承关系一样,resultMap也可以继承,在父类的基础上加入自己的属性

注意:这个过程是互斥的,也就是说,剩余的结果映射将被忽略。

如果匹配到的是technologyResult,那么就只有TechnologyBlog这个类会被加载,返回结果也是返回TechnologyBlog这个对象。

看完上面的代码你如果觉得太复杂,更倾向于简洁的映射风格,那么也可以换成以下这种写法:

<resultMap id="BlogResult" type="Blog">
    <id property="id" column="id" />
    <result property="name" column="name"/>
    <result property="pwd" column="pwd"/>

    <discriminator javaType="int" column="type_blog">
        <case value="1" resultType="TechnologyBlog">
            <result property="study" column="study" />
        </case>
        <case value="2" resultType="PlayBlog"/>
        <result property="game" column="game" />
    </case>
</discriminator>
        </resultMap>

总结

1、关联-association

2、集合-collection

3、association是用于一对一和多对一,而collection是用于一对多的关系

4、JavaType和ofType都是用来指定对象类型的

  • JavaType是用来指定pojo中属性的类型

  • ofType指定的是映射到list集合属性中pojo的类型。


结语

不知不觉,已经写到凌晨了,回头一看,原来,十一月已经结束了。

以上就是一心同学对MyBatis最强大的元素ResultMap的讲解,通过文档的整理+上机实操,说实话确实耗费了我好大精力,因为这个知识点的量确实很多,但同时在这个过程也让我认识到了ResultMap的强大之处,明天一心同学将满血复活,也就是下一篇博客,将为大家讲解映射文件中的自动映射。

十二月,你好。

  • 19
    点赞
  • 79
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一心同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值