@

在一对多的关系中, 主表的数据回对应关联表中的多条数据。 因此, 查询时就会查询出多条结果, 所以, 向类似的情况我们会使用 List 来进行存储关联表中获取到的信息。

1 数据准备

创建以下的名为 mybatis 的数据库, 并在其下创建4个表。

在此就不贴出来建表的 SQL 语句了 , 感兴趣的可以去我的 Github:mybatis-mapping 中获取。

1.2 实体类, 接口和XML

使用 mybatis-代码生成器 生成相应的实体类, 接口和XML。

以上为生成的项目结构。

2 一对多映射

2.1 collection集合映射

2.1.1 创建结果实体类

我们需要创建一个 BlogPostBO,

public class BlogPostBO extends Blog {

    private List<Post> posts;

    public List<Post> getPosts() {
return posts;
} public void setPosts(List<Post> posts) {
this.posts = posts;
}
}

该类继承于 Blog 类, 并多了一个链表成员变量 posts, 我们后续获取到的发布的文章都在此链表中。

2.1.2 创建结果集

刚开始时, 是这样子创建的。

<resultMap id="BlogPostBO"  type="com.homejim.mybatis.entity.BlogPostBO" extends="BaseResultMap">
<collection property="posts" columnPrefix="post_" ofType="com.homejim.mybatis.entity.Post">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="blog_id" jdbcType="INTEGER" property="blogId" />
<result column="draft" jdbcType="INTEGER" property="draft" />
<result column="content" jdbcType="LONGVARCHAR" property="content" />
</collection>
</resultMap>

此处注意一个问题, 在 collection 中, 我们用的是 ofType 来表示 List 中的 Pojo 的属性。而不是 type

因为我们内部 Post 有对应的结果集, 可以引用另一个 Mapper 中的结果集, 就可以简化变成下面这样子:

<resultMap id="BlogPostBO"  type="com.homejim.mybatis.entity.BlogPostBO" extends="BaseResultMap">
<collection property="posts" columnPrefix="post_" resultMap="com.homejim.mybatis.mapper.PostMapper.ResultMapWithBLOBs" />
</resultMap>

可以简单了好多。

2.1.3 创建对应的方法和XML

首先就是在对应的 Mapper 接口下创建方法:

    /**
* 获取博客及其发布的文章内容 一对多
* @return
*/
List<BlogPostBO> selectBlogAndPostList();

同时在 XML 中创建对应的 SQL 语句:

<select id="selectBlogAndPostList"  resultMap="BlogPostBO">
SELECT
b.id,
b.title,
b.author_id,
p.id as post_id,
p.blog_id as post_blog_id,
p.draft as post_draft,
p.content as post_content
FROM blog b left join post p on p.blog_id=b.id
</select>

2.1.4 测试

    /**
* resultMap + collection 一对多映射
*/
@Test
public void testSelectBlogAndPostListByBlog() {
SqlSession sqlSession = sqlSessionFactory.openSession();
BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
List<BlogPostBO> blogPostBOs = blogMapper.selectBlogAndPostList(); sqlSession.close(); for (int i = 0; i < blogPostBOs.size(); i++) {
BlogPostBO blogPostBO = blogPostBOs.get(i);
System.out.println(blogPostBO.getTitle()); for (int j = 0; j < blogPostBO.getPosts().size(); j++) {
System.out.println(blogPostBO.getPosts().get(j).getContent());
} System.out.println("=============这是对象分割线===============");
}
}

测试结果

可以看出, 已经获取到了。

2.1.5 结果合并原理

刚开始的时候, 我们获取到的结果在数据库中应该是这样子的

那么, 结果是怎么变成下面这样子的呢?

2.1.5.1 合并的依据

mybatis 在处理结果时, 会判断对象是否相同, 如果相同则会将结果与之前的结果进行合并。

那么, 结果是否相同是如何判断的呢?

首先是通过 id的比较, 如果 id 没有配置则比较每一个字段(此时, 只要有一个字段不同的对象不同)

2.1.5.2 id 的作用

在生成的 XML 中, 如果我们有主键, 一般会生成一个对应的 id 属性。

id 属性就可以用来判断获取到的数据是否属于同一个对象

在以上的例子中, 数据库中查询出来有三个 id=1, 则 mybatis 在处理结果时就可以知道这三条数据对应相同的对象, 从而将他们合并。

2.1.5.3 id 的作用验证

我们可以测试一下, 将 BlogMapper.xmlBaseResultMap 改成 titleid, 然后将数据库改一下

那么, 此时博客 id=1 和 博客 id=2title 都为 “小明的博客”, 那么, 按照以上的推论, 此两博客的对象应该合二为一。

真相揭晓

小王的博客消失了, 小明的博客发表文章数量从 3 变为 5 , 因为合并了小王博客发布的文章数量。

2.1.5.4 建议

建议尽量配置 id 的属性, 如果没有这个属性, 则 mybatis 在进行结果合并时效率会低很多。

2.2 collection 嵌套查询方式

2.2.1 创建结果实体类

我们需要创建一个 BlogPostBO,

public class BlogPostBO extends Blog {

    private List<Post> posts;

    public List<Post> getPosts() {
return posts;
} public void setPosts(List<Post> posts) {
this.posts = posts;
}
}

该类继承于 Blog 类, 并多了一个链表成员变量 posts, 我们后续获取到的发布的文章都在此链表中。

2.2.2 创建结果集

结果集中多了一个 select 的属性, 同时, 需要相应的指定 postscolumn

<resultMap id="BlogPostCustom"  type="com.homejim.mybatis.entity.BlogPostBO" extends="BaseResultMap">
<collection property="posts" column="{blogId=id}"
select="com.homejim.mybatis.mapper.PostMapper.selectPostByBlogId" fetchType="lazy" />
</resultMap>

重要说明:

  1. column 中, 需要填写 {属性名=列名(别名)} 的方式(如果只有一个参数, 也可以直接填列名传入参数的即可)。 如果是传递多个参数, 则是 {属性名1=列名1, 属性名2=列名2}

  2. select 属性值 com.homejim.mybatis.mapper.PostMapper.selectPostByBlogId, 对应的 parameterTypejava.util.Map(也可以不填)。

  3. fetchType 的属性值 lazy(延迟加载, 还需要相应的配置) 或 eager。(更详细的参考我上篇文章[mybatis-高级结果映射之一对一]

2.2.3 创建对应的方法和XML

主方法

    /**
* 获取博客及其发布的文章内容 一对多:延迟加载
* @return
*/
List<BlogPostBO> selectBlogAndPostListLazy();

主方法对应的 XML

<select id="selectBlogAndPostListLazy"  resultMap="BlogPostCustom">
SELECT
b.id,
b.title,
b.author_id
FROM blog b
</select>

嵌套方法

    /**
* 根据博客 id 获取发布的文章信息
* @param blogId 博客 id
* @return
*/
List<Post> selectPostByBlogId(int blogId);

嵌套方法对应 XML

  <select id="selectPostByBlogId" parameterType="java.util.Map" resultMap="ResultMapWithBLOBs">
select
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from post
where blog_id = #{blogId,jdbcType=INTEGER}
</select>

2.2.4 测试

    /**
* resultMap + collection 一对多映射, 嵌套查询
*/
@Test
public void testSelectBlogAndPostListByBlogLazy() {
SqlSession sqlSession = sqlSessionFactory.openSession();
BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
List<BlogPostBO> blogPostBOs = blogMapper.selectBlogAndPostListLazy(); for (int i = 0; i < blogPostBOs.size(); i++) {
BlogPostBO blogPostBO = blogPostBOs.get(i);
System.out.println(blogPostBO.getTitle());
List<Post> posts = blogPostBO.getPosts(); for (int j = 0; j < posts.size(); j++) {
System.out.println(blogPostBO.getPosts().get(j).getContent());
} System.out.println("=============这是对象分割线===============");
}
}

可以看到, 只有在需要使用对象的时候, 才会进行延迟加载。

3 代码

我的 Github:mybatis-mapping

一起学 mybatis

你想不想来学习 mybatis? 学习其使用和源码呢?那么, 在博客园关注我吧!!

我自己打算把这个源码系列更新完毕, 同时会更新相应的注释。快去 star 吧!!

mybatis最新源码和注释

mybatis-高级结果映射之一对多的更多相关文章

  1. Mybatis高级结果映射

    有时侯,我们用SQL取得的结果需要映射到类似Map<key, Bean>这样的数据结构中或是映射到多个实体类中时,我们就需要使用到resultMap.下面用3个例子说明Mybatis高级结 ...

  2. Mybatis 高级结果映射 ResultMap Association Collection

    在阅读本文章时,先说几个mybatis中容易混淆的地方: 1. mybatis中的列不是数据库里的列而是查询里的列,可以是别名(如 select user_name as userName,这时col ...

  3. 转:mybatis 高级结果映射(http://blog.csdn.net/ilovejava_2010/article/details/8180521)

    高级结果映射 MyBatis的创建基于这样一个思想:数据库并不是您想怎样就怎样的.虽然我们希望所有的数据库遵守第三范式或BCNF(修正的第三范式),但它们不是.如果有一个数据库能够完美映射到所有应用程 ...

  4. MyBatis从入门到精通(十一):MyBatis高级结果映射之一对多映射

    最近在读刘增辉老师所著的<MyBatis从入门到精通>一书,很有收获,于是将自己学习的过程以博客形式输出,如有错误,欢迎指正,如帮助到你,不胜荣幸! 本篇博客主要讲解MyBatis中如何使 ...

  5. MyBatis框架——关系映射(一对多、多对多、多对一查询)

    关系映射 一.映射(多)对一.(一)对一的关联关系 1).使用列的别名 ①.若不关联数据表,则可以得到关联对象的id属性 ②.若还希望得到关联对象的其它属性.则必须关联其它的数据表 1.创建表: 员工 ...

  6. MyBatis从入门到精通(九):MyBatis高级结果映射之一对一映射

    最近在读刘增辉老师所著的<MyBatis从入门到精通>一书,很有收获,于是将自己学习的过程以博客形式输出,如有错误,欢迎指正,如帮助到你,不胜荣幸! 本篇博客主要讲解MyBatis中实现查 ...

  7. MyBatis高级查询

    -------------------------siwuxie095 MyBatis 高级查询 1.MyBatis 作为一个 ORM 框架,也对 SQL 的高级查询做了支持, MyBatis 高级查 ...

  8. 04—mybatis的关联映射

    mybatis的关联映射一对一一对多多对多 一.一对一(一个人只能有一个身份证号) 1.创建表创建表tb_card CREATE TABLE `tb_card` ( `id` int(11) NOT ...

  9. 六 mybatis高级映射(一对一,一对多,多对多)

    1  订单商品数据模型 以订单商品数据为模型,来对mybaits高级关系映射进行学习.

  10. mybatis高级映射(一对一,一对多)

    mybatis高级映射 一对一关联映射 需求:查询订单信息,关联查询用户信息(一个订单对应一个用户) (1)通过resultType实现 sql语句: select orders.* , USER.u ...

随机推荐

  1. Android Studio调试时遇见Install Repository and sync project的问题

    我们可以看到,报的错是“Failed to resolve: com.android.support:appcompat-v7:16.+”,也就是我们在build.gradle中最后一段中的compi ...

  2. vue缓存页面

    vue如何和ionic的缓存机制一样,可以缓存页面,在A页面跳转至B页面后返回A页面时A页面的数据还在? 在app.vue中将router-view使用keep-alive包起来,使用v-if来判断使 ...

  3. html常用标签学习笔记

    本文内容: 前言:本文讲述的内容包括几类常用标签,以及这些标签的一些常用属性(有一些属性由于已经有CSS样式来代替,所以对于一些不重要的这里选择不讲) 排版标签 段落标签:p div span 标题标 ...

  4. 惰性求值——lodash源码解读

    前言 lodash受欢迎的一个原因,是其优异的计算性能.而其性能能有这么突出的表现,很大部分就来源于其使用的算法--惰性求值. 本文将讲述lodash源码中,惰性求值的原理和实现. 一.惰性求值的原理 ...

  5. mysql练习----The JOIN operation

    game id mdate stadium team1 team2 1001 8 June 2012 National Stadium, Warsaw POL GRE 1002 8 June 2012 ...

  6. asp.net Web项目中使用Log4Net进行错误日志记录

      使用log4net可以很方便地为应用添加日志功能.应用Log4net,开发者可以很精确地控制日志信息的输出,减少了多余信息,提高了日志记录性能.同时,通过外部配置文件,用户可以不用重新编译程序就能 ...

  7. python黑帽子

    1.TCP客户端 #AF_INET 使用标准的IPv4地址或者主机名 #SOCK_STREAM是一个客户端 import socket target_host = 'www.google.com' t ...

  8. spring boot +RabbitMQ +InfluxDB+Grafara监控实践

    本文需要有相关spring boot 或spring cloud 相关微服务框架的基础,如果您具备相关基础可以很容易的实现下述过程!!!!!!! 希望本文的所说对需要的您有所帮助 从这里我们开始进入闲 ...

  9. C语言入坑指南-被遗忘的初始化

    前言 什么是初始化?为什么要初始化?静态变量和局部变量的初始化又有什么区别?实际应用中应该怎么做?本文将一一回答这些问题. 什么是初始化 初始化指的是对数据对象或者变量赋予初始值.例如: int va ...

  10. 《Java大学教程》—第19章 改进用户界面

    用户与程序交互的媒介称为用户界面(user interface)或人机界面(human-computer interface). 19.2    Border接口8个实现Border接口的标准边框类: ...