MyBatis 之Result Maps最精华部分

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatis 之Result Maps最精华部分相关的知识,希望对你有一定的参考价值。

案例:https://github.com/sun2shadow/simpleMybatis

resultMap 元素是 MyBatis 中最重要最强大的元素。

先看一个简单的映射:

<select id="selectUsers" resultType="map">
  select id, username, hashedPassword
  from some_table
  where id = #{id}
</select>

它把所有的列映射到HashMap的主键上.但是实践中经常把resultType类型制定为JavaBeans或POJOs,如以下语句:

<select id="selectUsers" resultType="com.someapp.model.User">
  select id, username, hashedPassword
  from some_table
  where id = #{id}
</select>

高级映射是开发中常用的形式:

resultMap概念视图:

  • constructor - 类在实例化时,用来注入结果到构造方法中

    • idArg - ID 参数;标记结果作为 ID 可以帮助提高整体效能

    • arg - 注入到构造方法的一个普通结果

  • id – 一个 ID 结果;标记结果作为 ID 可以帮助提高整体效能

  • result – 注入到字段或 JavaBean 属性的普通结果

  • association – 一个复杂的类型关联;许多结果将包成这种类型

    • 嵌入结果映射 – 结果映射自身的关联,或者参考一个

  • collection – 复杂类型的集

    • 嵌入结果映射 – 结果映射自身的集,或者参考一个

  • discriminator – 使用结果值来决定使用哪个结果映射

    • 嵌入结果映射 – 这种情形结果也映射它本身,因此可以包含很多相                      同的元素,或者它可以参照一个外部的结果映射。

    • case – 基于某些值的结果映射

ResultMap Attributes
属性描述
id当前命名空间中的一个唯一标识,用于标识一个result map.
type类的全限定名, 或者一个类型别名 (内置的别名可以参考上面的表格).
autoMapping如果设置这个属性,MyBatis将会为这个ResultMap开启或者关闭自动映射。这个属性会覆盖全局的属性autoMappingBehavior。默认值为:unset。
<resultMap id="detailedBlogResultMap" type="Blog">
</resultMap>

Id&result

<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>

id 和 result 都映射一个单独列的值到简单数据类型(字符 串,整型,双精度浮点数,日期等)的单独属性或字段

Id and Result Attributes
属性描述
property映射到列结果的字段或属性。如果匹配的是存在的,和给定名称相同 的 JavaBeans 的属性,那么就会使用。否则 MyBatis 将会寻找给定名称 property 的字段。这两种情形你可以使用通常点式的复杂属性导航。比如,你 可以这样映射一些东西: “username” ,或者映射到一些复杂的东西: “address.street.number” 。
column从数据库中得到的列名,或者是列名的重命名标签。这也是通常和会 传递给 resultSet.getString(columnName)方法参数中相同的字符串。
javaType一个 Java 类的完全限定名,或一个类型别名(参考上面内建类型别名 的列表) 。如果你映射到一个 JavaBean,MyBatis 通常可以断定类型。 然而,如果你映射到的是 HashMap,那么你应该明确地指定 javaType 来保证所需的行为。
jdbcType在这个表格之后的所支持的 JDBC 类型列表中的类型。JDBC 类型是仅 仅需要对插入,更新和删除操作可能为空的列进行处理。这是 JDBC jdbcType 的需要,而不是 MyBatis 的。如果你直接使用 JDBC 编程,你需要指定 这个类型-但仅仅对可能为空的值。
typeHandler我们在前面讨论过默认的类型处理器。使用这个属性,你可以覆盖默 认的类型处理器。这个属性值是类的完全限定名或者是一个类型处理 器的实现,或者是类型别名。

关联:连表查询时需要关联映射关系.property:blog中author变量,column表的author的外建,javaType关联的entity

<association property="author" column="blog_author_id" javaType="Author">
  <id property="id" column="author_id"/>
  <result property="username" column="author_username"/>
</association>

通过映射关系来告诉MyBatis如何加载关联关系,MyBatis提供了2中方式:

  • 嵌套查询:通过执行另外一个 SQL 映射语句来返回预期的复杂类型。

  • 嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集。首先,然让我们来查看这个元素的属性。所有的你都会看到,它和普通的只由 select 和

resultMap 属性的结果映射不同。

关联的嵌套查询:

<resultMap id="blogResult" type="Blog">
  <association property="author" column="author_id" javaType="Author" select="selectAuthor"/>
</resultMap>
<select id="selectBlog" resultMap="blogResult">
  SELECT * FROM BLOG WHERE ID = #{id}
</select>
<select id="selectAuthor" resultType="Author">
  SELECT * FROM AUTHOR WHERE ID = #{id}
</select>

一个来加载博客,另外一个来加载作者,这种方式最大的问题就是N+1查询问题,查询一条博客有N个作者需要查询作者表N次.

关联的嵌套结果:

先看一个这样的语句:查询blog的作者和联合作者,作者和联合作者的id不能都叫author_id,否则会引起冲突.

<select id="selectBlog" resultMap="blogResult">
  select
    B.id            as blog_id,
    B.title         as blog_title,
    A.id            as author_id,
    A.username      as author_username,
    A.password      as author_password,
    A.email         as author_email,
    A.bio           as author_bio,
    CA.id           as co_author_id,
    CA.username     as co_author_username,
    CA.password     as co_author_password,
    CA.email        as co_author_email,
    CA.bio          as co_author_bio
  from Blog B
  left outer join Author A on B.author_id = A.id
  left outer join Author CA on B.co_author_id = CA.id
  where B.id = #{id}</select>

首先定义author的结果映射:

<resultMap id="authorResult" type="Author">
  <id property="id" column="author_id"/>
  <result property="username" column="author_username"/>
  <result property="password" column="author_password"/>
  <result property="email" column="author_email"/>
  <result property="bio" column="author_bio"/>
</resultMap>

其次定义blog的resultMap,通过columnPrefix来指定前缀以此来区分是主作者还是联合作者.

<resultMap id="blogResult" type="Blog">
  <id property="id" column="blog_id" />
  <result property="title" column="blog_title"/>
  <association property="author" resultMap="authorResult" />
  <association property="coAuthor" resultMap="authorResult" columnPrefix="co_" />
</resultMap>

看完了关联,再来看集合就容易多了,基本上是相似的.

private List<Post> posts;

这种关系就需要用到集合,通过ofType指定,列表内数据的类型是Post.

<select id="selectBlog" resultMap="blogResult">
  select
  B.id as blog_id,
  B.title as blog_title,
  B.author_id as blog_author_id,
  P.id as post_id,
  P.subject as post_subject,
  P.body as post_body,
  from Blog B
  left outer join Post P on B.id = P.blog_id
  where B.id = #{id}
</select>

上面这个查询需要映射的关系如下:collection 中property属性是blog中的变量posts,看上面的变量声明

<resultMap id="blogResult" type="Blog">
  <id property="id" column="blog_id" />
  <result property="title" column="blog_title"/>
  <collection property="posts" ofType="Post">
    <id property="id" column="post_id"/>
    <result property="subject" column="post_subject"/>
    <result property="body" column="post_body"/>
  </collection>
</resultMap>

下面来简单的说明一下鉴别器:根据查询结果的不同来选择不同的映射器.

鉴别器这个例子比较有意思,查询车辆信息,返回不同类型的车辆,有轿车,货车,SUV等不同类型有不同的映射结果.

<resultMap id="vehicleResult" type="Vehicle">
  <id property="id" column="id" />
  <result property="vin" column="vin"/>
  <result property="year" column="year"/>
  <result property="make" column="make"/>
  <result property="model" column="model"/>
  <result property="color" column="color"/>
  <discriminator javaType="int" column="vehicle_type">
    <case value="1" resultMap="carResult"/>
    <case value="2" resultMap="truckResult"/>
    <case value="3" resultMap="vanResult"/>
    <case value="4" resultMap="suvResult"/>
  </discriminator>
</resultMap>

如果类型是car的话,则按照carResult来映射结果:

<resultMap id="carResult" type="Car">
  <result property="doorCount" column="door_count" />
</resultMap>

这种情况下只有 doorCount 属性会被加载.如果 Car 是一个 Vehicle 实例。因此,我们想要剩余的属性也被加载。我们设置的结果映射的 简单改变如下。

<resultMap id="carResult" type="Car" extends="vehicleResult">
  <result property="doorCount" column="door_count" />
</resultMap>


本文出自 “数据挖掘工程师的成长历程” 博客,请务必保留此出处http://qianqiansun.blog.51cto.com/13271301/1965574

以上是关于MyBatis 之Result Maps最精华部分的主要内容,如果未能解决你的问题,请参考以下文章

笔记:MyBatis Mapper XML文件详解 - Result Maps

A query was run and no Result Maps were found for...原来是mapper.xml文件出了问题,是使用MyBatis最常见的一种错误

Mybatis异常_02_Result Maps collection already contains value for

MyBatis出错Result Maps collection does not contain value for java.lang.Integer

Mybatis "java.lang.IllegalArgumentException: Result Maps collection already contains value for&

MyBatis Generator报错:Result Maps collection already contains value for xxxMapper.BaseResultMap(