mybatis-高级结果映射之一对一
mybatis的高级结果映射可以很轻松的帮助我们处理一对一, 一对多的数据关系。
1 数据准备
1.1 数据库
创建以下的名为 mybatis 的数据库, 并在其下创建4个表。
在此就不贴出来建表的 SQL 语句了 , 感兴趣的可以去我的 Github:mybatis-mapping 中获取。
1.2 实体类, 接口和XML
使用 mybatis-代码生成器 生成相应的实体类, 接口和XML。
以上为生成的项目结构。
2 一对一映射
创建的表中, author 和 blog 就是一对一的关系。
我们希望找到一个blog, 然后就会把它的作者信息也关联出来。
2.1 resultType 方式一
注意:resultType方式要求获取到的列和成员变量名一致。
2.1.1 创建对象
创建一个类BlogCustom, 该类继承于 Blog 类, 在该类上添加 Author 对象作为成员变量
2.1.2 创建接口方法和XML 语句
    BlogBO selectBoById(int id);
    /**
     * 根据博客的 id 获取博客及作者的信息
     * @param id
     * @return
     */
    BlogCustom selectCutomById(int id);
对应的 XML 语句:
  <select id="selectCutomById" parameterType="java.lang.Integer" resultType="com.homejim.mybatis.entity.BlogCustom">
   SELECT
    b.id,
    b.title,
    b.author_id AS authorId,
    a.id AS "author.id",
    a.username AS "author.username",
    a.password AS "author.password" ,
    a.email AS "author.email"
  FROM blog b LEFT JOIN author a ON b.author_id=a.id
 where b.id = #{id,jdbcType=INTEGER}
  </select>
通过 author.username 这种方式可以设定 author 对象中的 username 属性。
2.1.3 测试
    @Test
    public void testSelectCustomById() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
        BlogCustom blogCustom = blogMapper.selectCutomById(1);
        System.out.println(ToStringBuilder.reflectionToString(blogCustom, ToStringStyle.MULTI_LINE_STYLE));
    }
运行后的结果
有时候, 我们获取的另外的属性不多, 则我们也可以选择下面的方式二。
2.2 resultType 方式二
2.2.1 创建对象
创建一个类BlogBO, 该类继承于 Blog 类, 在该类上添加 Author 中的成员变量作为该类自己的成员变量。
2.2.2 创建接口方法和XML 语句
接口方法
    /**
     * 根据博客的 id 获取博客及作者的信息
     * @param id
     * @return
     */
    BlogBO selectBoById(int id);
XML 对应的 SQL , 其中 resultType 是上面定义的实体对象。
  <select id="selectBoById" parameterType="java.lang.Integer" resultType="com.homejim.mybatis.entity.BlogBO">
    select
     b.id, b.title, b.author_id as authorId, a.id as userId, a.username, a.email
    from blog b left join author a on b.author_id=a.id
    where b.id = #{id,jdbcType=INTEGER}
  </select>
2.2.3 测试
创建一个测试例子。
    @Test
    public void testSelectBoById() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
        BlogBO blogBO = blogMapper.selectBoById(1);
        System.out.println(ToStringBuilder.reflectionToString(blogBO, ToStringStyle.MULTI_LINE_STYLE));
    }
测试结果
2.3 resultMap 方式
2.3.1 创建对象
创建一个类BlogCustom, 该类继承于 Blog 类, 在该类上添加 Author 对象作为成员变量

2.3.2 创建对应 resultMap
对应创建一个 resultMap
  <resultMap id="BOResultMap" type="com.homejim.mybatis.entity.BlogCustom" extends="BaseResultMap">
    <result column="username" jdbcType="VARCHAR" property="author.username" />
    <result column="user_id" jdbcType="VARCHAR" property="author.id" />
    <result column="email" jdbcType="VARCHAR" property="author.email" />
  </resultMap>
2.3.3 创建接口方法和XML 语句
    /**
     * 根据博客的 id 获取博客及作者的信息, resultMap 方式
     * @param id
     * @return
     */
    BlogCustom selectCutomByIdMap(int id);
SQL 语句得出的列名与 BOResultMap 一致。
  <select id="selectCutomByIdMap" parameterType="java.lang.Integer" resultMap="BOResultMap">
   SELECT
    b.id,
    b.title,
    b.author_id AS authorId,
    a.id AS "user_id",
    a.username,
    a.email
  FROM blog b LEFT JOIN author a ON b.author_id=a.id
 where b.id = #{id,jdbcType=INTEGER}
  </select>
2.3.4 测试
    /**
     *  resultMap 方式一测试
     */
    @Test
    public void testSelectCustomByIdMap() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
        BlogCustom blogCustom = blogMapper.selectCutomByIdMap(1);
        System.out.println(ToStringBuilder.reflectionToString(blogCustom, ToStringStyle.MULTI_LINE_STYLE));
    }
得出的结果
其实该类型也可以配置对应 BlogBO 类对应的方式, 在此不做过多的讲解。
2.4 resultMap + association 方式
2.4.1 创建对象
创建一个类BlogCustom, 该类继承于 Blog 类, 在该类上添加 Author 对象作为成员变量
2.4.2 创建 resultMap
  <resultMap id="CustomResultMap" type="com.homejim.mybatis.entity.BlogCustom" extends="BaseResultMap">
     <association property="author" javaType="com.homejim.mybatis.entity.Author">
       <id column="user_id" jdbcType="INTEGER" property="id" />
       <result column="username" jdbcType="VARCHAR" property="username" />
       <result column="email" jdbcType="VARCHAR" property="email" />
     </association>
  </resultMap>
或者, 可以引用别的 Mapper 中的结果集。
  <resultMap id="CustomResultMap" type="com.homejim.mybatis.entity.BlogCustom" extends="BaseResultMap">
     <association property="author" javaType="com.homejim.mybatis.entity.Author" resultMap="com.homejim.mybatis.mapper.AuthorMapper.BaseResultMap">
     </association>
  </resultMap>
2.4.3 创建接口方法和XML 语句
    /**
     * 根据博客的 id 获取博客及作者的信息, resultMap + association方式
     * @param id
     * @return
     */
    BlogCustom selectCutomByIdAMap(int id);
SQL 语句
<select id="selectCutomByIdAMap" parameterType="java.lang.Integer" resultMap="CustomResultMap">
   SELECT
    b.id,
    b.title,
    b.author_id AS authorId,
    a.id AS "user_id",
    a.username,
    a.email
  FROM blog b LEFT JOIN author a ON b.author_id=a.id
 where b.id = #{id,jdbcType=INTEGER}
  </select>
2.4.4 测试
    /**
     *  resultMap + association 方式测试
     */
    @Test
    public void testSelectCustomByIdAMap() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
        BlogCustom blogCustom = blogMapper.selectCutomByIdAMap(1);
        System.out.println(ToStringBuilder.reflectionToString(blogCustom, ToStringStyle.MULTI_LINE_STYLE));
    }
结果
2.5 resultMap + association 嵌套查询
以上几种方法都是通过 left join 的 SQL 语句获取多个对象的结果。 还可以经过简单的 SQL 语句, 多次查询而转化为我们需要的结果。
2.5.1
2.5.1 创建对象
创建一个类BlogCustom, 该类继承于 Blog 类, 在该类上添加 Author 对象作为成员变量
2.5.2 创建 resultMap
  <resultMap id="blogAuthorMap" type="com.homejim.mybatis.entity.BlogCustom" extends="BaseResultMap">
    <association property="author" column="author_id" select="com.homejim.mybatis.mapper.AuthorMapper.selectById" fetchType="eager" />
  </resultMap>
该结果集与之前的不同了, association 标签中使用了 select 属性。
select: 另一个查询的 id, mybatis 会额外执行这个查询来获取嵌套的结果
column: 列名(别名), 将主查询中的列作为嵌套查询的参数, 多个参数使用逗号(英文)分隔开。
fetchType: 数据加载的方式, 可选择为 lazy(延迟加载) 或者 eager(积极加载), 该配置会覆盖全局的 lazyLoadingEnabled 配置。
2.5.3 创建接口方法和XML 语句
    /**
     * 根据博客的 id 获取博客及作者的信息, resultMap + association嵌套方式
     * @param id
     * @return
     */
    BlogCustom selectBlogAndAuthorByIdSelect(int id);
获取的数据是博客和用户的信息, 以下的 SQL 只是获取博客信息, 用户信息通过 com.homejim.mybatis.mapper.AuthorMapper.selectById 获取。
  <select id="selectBlogAndAuthorByIdSelect" parameterType="java.lang.Integer" resultMap="blogAuthorMap">
   SELECT
    b.id,
    b.title,
    b.author_id
  FROM blog b
 where b.id = #{id,jdbcType=INTEGER}
  </select>
com.homejim.mybatis.mapper.AuthorMapper.selectById 是一个全限定名, 即 AuthorMapper 下的 selectById 方法
    /**
     * 嵌套查询使用的方法
     * @param id
     * @return
     */
    Author selectById(Integer id);
对应的 SQL
  <select id="selectById" parameterType="java.lang.Integer" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List" />
    from author
    where id = #{id}
  </select>
2.5.4 测试
使用时, 调用 selectBlogAndAuthorByIdSelect 方法即可。
    /**
     *  resultMap + association 嵌套查询方式测试
     */
    @Test
    public void testSelectBlogAndAuthorByIdSelect() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
        BlogCustom blogCustom = blogMapper.selectBlogAndAuthorByIdSelect(1);
        System.out.println(ToStringBuilder.reflectionToString(blogCustom, ToStringStyle.MULTI_LINE_STYLE));
        Assert.assertNotNull(blogCustom);
        Assert.assertNotNull(blogCustom.getAuthor());
    }
输出, 会发送两次 SQL 语句。
可以看到, 上面的结果示意图中, 发送了两次 SQL 。
2.5.5 延迟加载
如果是一个对象中只是包含一两个对象, 使用上面的方式还好。 但是如果包含有很多, 那要一次性发送很多次 SQL, 性能上就会很有影响。延迟加载可以解决此类的问题。
延迟加载就是说,只有在调用内部的对象时, 才会把获取该对象的 SQL 发送出去。
更改结果集
  <resultMap id="blogAuthorMapLazy" type="com.homejim.mybatis.entity.BlogCustom" extends="BaseResultMap">
    <association fetchType="lazy" property="author" column="author_id" select="com.homejim.mybatis.mapper.AuthorMapper.selectById" />
  </resultMap>
将上面的查询中的结果集更改 resultMap="blogAuthorMapLazy"
  <select id="selectBlogAndAuthorByIdSelect" parameterType="java.lang.Integer" resultMap="blogAuthorMapLazy"> <!--resultMap="blogAuthorMap"-->
    SELECT
    b.id,
    b.title,
    b.author_id
  FROM blog b
 where b.id = #{id,jdbcType=INTEGER}
  </select>
更改延迟加载总开关
 <setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
测试
注意: 延迟加载是在
SqlSession的声明周期内的, 如果超出该声明周期, 如 spring 中, 只能在 Service 层使用延迟加载的对象, 如果返回Controller层在获取延迟加载属性, 则会抛出异常。
有时候, 我们配置了延迟加载, 但是却想要一次性加载, 怎么办?
有一个配置属性可以帮我们解决 lazyLoadTriggerMethods, 它的默认配置如下:
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
就是说我们使用上面配置中的任何一个方法(上面的是默认的, 我们可以不配置), 就可以加载属性啦。
测试
    /**
     *  resultMap + association 嵌套查询方式测试(延迟加载不延迟lazyLoadTriggerMethods)
     */
    @Test
    public void testSelectBlogAndAuthorByIdSelectTrigger() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
        BlogCustom blogCustom = blogMapper.selectBlogAndAuthorByIdSelect(1);
        blogCustom.equals(null);
        Assert.assertNotNull(blogCustom);
        sqlSession.close();
        System.out.println("开始使用author对象");
        Assert.assertNotNull(blogCustom.getAuthor());
    }
结果
3. 代码
本来还要写的一对多, 鉴别器的, 但由于篇幅的原因, 后续继续吧。
一起学 mybatis
你想不想来学习 mybatis? 学习其使用和源码呢?那么, 在博客园关注我吧!!
我自己打算把这个源码系列更新完毕, 同时会更新相应的注释。快去 star 吧!!

mybatis-高级结果映射之一对一的更多相关文章
- MyBatis从入门到精通(九):MyBatis高级结果映射之一对一映射
		最近在读刘增辉老师所著的<MyBatis从入门到精通>一书,很有收获,于是将自己学习的过程以博客形式输出,如有错误,欢迎指正,如帮助到你,不胜荣幸! 本篇博客主要讲解MyBatis中实现查 ... 
- Mybatis高级结果映射
		有时侯,我们用SQL取得的结果需要映射到类似Map<key, Bean>这样的数据结构中或是映射到多个实体类中时,我们就需要使用到resultMap.下面用3个例子说明Mybatis高级结 ... 
- MyBatis从入门到精通(第6章):MyBatis 高级查询->6.1.1高级结果映射之一对一映射
		jdk1.8.MyBatis3.4.6.MySQL数据库5.6.45.IntelliJ IDEA 2019.2.4 本章主要包含的内容为 MyBatis 的高级结果映射,主要处理数据库一对一.一对多的 ... 
- Mybatis 高级结果映射 ResultMap Association Collection
		在阅读本文章时,先说几个mybatis中容易混淆的地方: 1. mybatis中的列不是数据库里的列而是查询里的列,可以是别名(如 select user_name as userName,这时col ... 
- 转:mybatis 高级结果映射(http://blog.csdn.net/ilovejava_2010/article/details/8180521)
		高级结果映射 MyBatis的创建基于这样一个思想:数据库并不是您想怎样就怎样的.虽然我们希望所有的数据库遵守第三范式或BCNF(修正的第三范式),但它们不是.如果有一个数据库能够完美映射到所有应用程 ... 
- MyBatis从入门到精通(十一):MyBatis高级结果映射之一对多映射
		最近在读刘增辉老师所著的<MyBatis从入门到精通>一书,很有收获,于是将自己学习的过程以博客形式输出,如有错误,欢迎指正,如帮助到你,不胜荣幸! 本篇博客主要讲解MyBatis中如何使 ... 
- MyBatis高级查询
		-------------------------siwuxie095 MyBatis 高级查询 1.MyBatis 作为一个 ORM 框架,也对 SQL 的高级查询做了支持, MyBatis 高级查 ... 
- 【Mybatis高级映射】一对一映射、一对多映射、多对多映射
		前言 当我们学习heribnate的时候,也就是SSH框架的网上商城的时候,我们就学习过它对应的高级映射,一对一映射,一对多映射,多对多映射.对于SSM的Mybatis来说,肯定也是差不多的.既然开了 ... 
- 六 mybatis高级映射(一对一,一对多,多对多)
		1 订单商品数据模型 以订单商品数据为模型,来对mybaits高级关系映射进行学习. 
- Mybatis(四) 高级映射,一对一,一对多,多对多映射
		天气甚好,怎能不学习? 一.单向和双向 包括一对一,一对多,多对多这三种情况,但是每一种又分为单向和双向,在hibernate中我们就详细解析过这单向和双向是啥意思,在这里,在重复一遍,就拿一对多这种 ... 
随机推荐
- B-树、B+树
			B-树 用来在外部存储中组织数据. 严格来说,2-3树.2-3-4树都是B-树的特例:但B树更强调它的节点有很多个子节点,B-树中的节点可以有几十或几百个子节点. B-树也可以是查找树,也可以不是查找 ... 
- Django ModelForm 小实例1
			1.models.py ASSET_STATUS = ( (str(1), u"使用中"), (str(2), u"未使用"), (str(3), u" ... 
- JS笔记(二):对象
			(一) 对象 对象是JS的基本数据类型,类似于python的字典.然而对象不仅仅是键值对的映射,除了可以保持自有的属性,JS对象还可以从一个称为原型的对象继承属性,对象的方法通常是继承的属性.(这种对 ... 
- Linux  MySql 安装与配置
			为什么选择MySQL数据库? 毫无疑问,绝大多数的使用linux操作系统的大中小型互联网网站都在使用MySQL作为其后端的数据库存储,从大型的BAT门户,到电商平台,分类门户等无一例都使用MySQL数 ... 
- Hadoop2.7.6_06_mapreduce参数优化
			MapReduce重要配置参数 1. 资源相关参数 //以下参数是在用户自己的mr应用程序中配置就可以生效 () mapreduce.map.memory.mb: 一个Map Task可使用的资源上限 ... 
- 联想笔记本Y7000P安装nvidia,cuda,tensorflow,pytorch
			Y7000P电脑环境i7处理器,1060显卡,16g内存,win10家庭版(系统版本号1809),在联想官网升级过bios,所有驱动都是最新.(截止时间点2019年3月1日) python3.5 安装 ... 
- 三叔学FPGA系列之二:Cyclone V中的POR、配置、初始化,以及复位
			对于FPGA内部的复位,之前一直比较迷,这两天仔细研究官方数据手册,解开了心中的诸多疑惑,感觉自己又进步了呢..... 原创不易,转载请转原文,注明出处,谢谢. 一.关于POR(Power-On ... 
- Nginx SSL TLS部署最佳实践
			本文介绍nginx在提供HTTPS时使用的一些其他配置选项. 虽然这些功能有助于优化nginx的SSL和TLS,但这不是一个完整对加固nginx的介绍. 确保您的服务器安全的最佳方法是不仅需要正确的配 ... 
- oracle语句insert into select如何加后续插入条件
			oracle语句insert into select如何加后续插入条件 2014-01-21 10:48匿名 分类:其他编程语言 | 浏览 2746 次 oracle中有批量插入语句insert i ... 
- vue的组件详解
			什么是组件 组件(Component)是 Vue.js 最强大的功能之一.(好比电脑中的每一个元件(键盘,鼠标,CPU),它是一个具有独立的逻辑和功能或界面,同时又能根据规定的接口规则进行互相融合,变 ... 
