Mybatis的ResultMap的使用

  本篇文章经过一个实际工做中遇到的例子开始吧:前端

  工程使用Spring+Mybatis+Mysql开发。具体的业务逻辑很重,对象之间一层一层的嵌套。和数据库表对应的是大量的model类,而和前端交互的是Vo类。如今须要作一个需求,有两种方式来实现:java

  •   使用现有的Service接口,或者本身在编写一些用到的接口,手动使用Java代码来分别调用Service接口来查出各个model,而后在业务层将model转换为vo,最后返回给前端json串。
  •       为需求相关的页面定义本身的vo,在vo中只定义前端用到的字段。而不是像第一种方式同样vo中一层一层的嵌套model。而后使用sql语句进行表关联,查询用到的字段。组装为vo直接返回

  例子到此结束,我想这两种完成方法大部分Java程序员都遇到过。两种方式都行得通,可是在项目的技术选型(Spring+Mybatis+Mysql)下面,哪一种跟好呢?程序员

  个人我的经验是若是业务逻辑不是太复杂,两种无所谓。可是若是业务逻辑太复杂,vo各类嵌套model和vo的话,我很是强烈的推荐第二种。(其实第二中可能hibernate更加适合,可是在此处不考虑),在笔者的此次需求中,使用第一中方式查询速度为5s,而改成第二种方式以后查询速度为60ms。提高的太快了。sql

  PS:上面的数字仅供参考,没太多实际意义,由于这个与具体代码的编写有关。数据库

      好了,言归正传。咱们来讲说第二种中的使用的Mybatis的ResultMap的使用。编程

  

  resultMap 元素是 MyBatis 中最重要最强大的元素。它就是让你远离 90%的须要从结果 集中取出数据的 JDBC 代码的那个东西, 并且在一些情形下容许你作一些 JDBC 不支持的事 情。 事实上, 编写类似于对复杂语句联合映射这些等同的代码, 也许能够跨过上千行的代码。 ResultMap 的设计就是简单语句不须要明确的结果映射,而不少复杂语句确实须要描述它们 的关系。json

你已经看到简单映射语句的示例了,但没有明确的 resultMap。好比:缓存

  

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

  这样一个语句简单做用于全部列被自动映射到 HashMap 的键上,这由 resultType 属性 指定。这在不少状况下是有用的,可是 HashMap 不能很好描述一个领域模型。那样你的应 用程序将会使用 JavaBeans 或 POJOs(Plain Old Java Objects,普通 Java 对象)来做为领域 模型。MyBatis 对二者都支持。看看下面这个 JavaBean:mybatis

  

package com.someapp.model;
public class User {
  private int id;
  private String username;
  private String hashedPassword;
  
  public int getId() {
    return id;
  }
  public void setId(int id) {
    this.id = id;
  }
  public String getUsername() {
    return username;
  }
  public void setUsername(String username) {
    this.username = username;
  }
  public String getHashedPassword() {
    return hashedPassword;
  }
  public void setHashedPassword(String hashedPassword) {
    this.hashedPassword = hashedPassword;
  }
}

  

基于 JavaBean 的规范,上面这个类有 3 个属性:id,username 和 hashedPassword。这些 在 select 语句中会精确匹配到列名。app

这样的一个 JavaBean 能够被映射到结果集,就像映射到 HashMap 同样简单。

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

  要记住类型别名是你的伙伴。使用它们你能够不用输入类的全路径。好比:

<!-- In mybatis-config.xml file -->
<typeAlias type="com.someapp.model.User" alias="User"/>

<!-- In SQL Mapping XML file -->
<select id="selectUsers" parameterType="int" resultType="User">
  select id, username, hashedPassword
  from some_table
  where id = #{id}
</select>

  这些状况下,MyBatis 会在幕后自动建立一个 ResultMap,基于属性名来映射列到 JavaBean 的属性上。若是列名没有精确匹配,你能够在列名上使用 select 字句的别名(一个 基本的 SQL 特性)来匹配标签。好比:

<select id="selectUsers" parameterType="int" resultType="User">
  select
    user_id             as "id",
    user_name           as "userName",
    hashed_password     as "hashedPassword"
  from some_table
  where id = #{id}
</select>

  ResultMap 最优秀的地方你已经了解了不少了,可是你尚未真正的看到一个。这些简 单的示例不须要比你看到的更多东西。 只是出于示例的缘由, 让咱们来看看最后一个示例中 外部的 resultMap 是什么样子的,这也是解决列名不匹配的另一种方式。

<resultMap id="userResultMap" type="User">
  <id property="id" column="user_id" />
  <result property="username" column="username"/>
  <result property="password" column="password"/>
</resultMap>

  引用它的语句使用 resultMap 属性就好了(注意咱们去掉了 resultType 属性)。好比:

<select id="selectUsers" parameterType="int" resultMap="userResultMap">
  select user_id, user_name, hashed_password
  from some_table
  where id = #{id}
</select>

  

若是世界老是这么简单就行了。

高级结果映射

MyBatis 建立的一个想法:数据库不用永远是你想要的或须要它们是什么样的。而咱们 最喜欢的数据库最好是第三范式或 BCNF 模式,但它们有时不是。若是可能有一个单独的 数据库映射,全部应用程序均可以使用它,这是很是好的,但有时也不是。结果映射就是 MyBatis 提供处理这个问题的答案。

好比,咱们如何映射下面这个语句?

<!-- Very Complex Statement -->
<select id="selectBlogDetails" parameterType="int" resultMap="detailedBlogResultMap">
  select
       B.id as blog_id,
       B.title as blog_title,
       B.author_id as blog_author_id,
       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,
       A.favourite_section as author_favourite_section,
       P.id as post_id,
       P.blog_id as post_blog_id,
       P.author_id as post_author_id,
       P.created_on as post_created_on,
       P.section as post_section,
       P.subject as post_subject,
       P.draft as draft,
       P.body as post_body,
       C.id as comment_id,
       C.post_id as comment_post_id,
       C.name as comment_name,
       C.comment as comment_text,
       T.id as tag_id,
       T.name as tag_name
  from Blog B
       left outer join Author A on B.author_id = A.id
       left outer join Post P on B.id = P.blog_id
       left outer join Comment C on P.id = C.post_id
       left outer join Post_Tag PT on PT.post_id = P.id
       left outer join Tag T on PT.tag_id = T.id
  where B.id = #{id}
</select>

  你可能想把它映射到一个智能的对象模型,包含一个做者写的博客,有不少的博文,每 篇博文有零条或多条的评论和标签。 下面是一个完整的复杂结果映射例子 (假设做者, 博客, 博文, 评论和标签都是类型的别名) 咱们来看看, 。 可是不用紧张, 咱们会一步一步来讲明。 当天最初它看起来使人生畏,但实际上很是简单。

<!-- Very Complex Result Map -->
<resultMap id="detailedBlogResultMap" type="Blog">
  <constructor>
    <idArg column="blog_id" javaType="int"/>
  </constructor>
  <result property="title" column="blog_title"/>
  <association property="author" javaType="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"/>
    <result property="favouriteSection" column="author_favourite_section"/>
  </association>
  <collection property="posts" ofType="Post">
    <id property="id" column="post_id"/>
    <result property="subject" column="post_subject"/>
    <association property="author" javaType="Author"/>
    <collection property="comments" ofType="Comment">
      <id property="id" column="comment_id"/>
    </collection>
    <collection property="tags" ofType="Tag" >
      <id property="id" column="tag_id"/>
    </collection>
    <discriminator javaType="int" column="draft">
      <case value="1" resultType="DraftPost"/>
    </discriminator>
  </collection>
</resultMap>

  

resultMap 元素有不少子元素和一个值得讨论的结构。 下面是 resultMap 元素的概念视图

resultMap

  • constructor - 类在实例化时,用来注入结果到构造方法中
    • idArg - ID 参数;标记结果做为 ID 能够帮助提升总体效能
    • arg - 注入到构造方法的一个普通结果
  • id – 一个 ID 结果;标记结果做为 ID 能够帮助提升总体效能
  • result – 注入到字段或 JavaBean 属性的普通结果
  • association – 一个复杂的类型关联;许多结果将包成这种类型
    • 嵌入结果映射 – 结果映射自身的关联,或者参考一个
  • collection – 复杂类型的集
    • 嵌入结果映射 – 结果映射自身的集,或者参考一个
  • discriminator – 使用结果值来决定使用哪一个结果映射
    • case – 基于某些值的结果映射
      • 嵌入结果映射 – 这种情形结果也映射它自己,所以能够包含不少相 同的元素,或者它能够参照一个外部的结果映射。
ResultMap Attributes
Attribute Description
id A unique identifier in this namespace that can be used to reference this result map.
type A fully qualified Java class name, or a type alias (see the table above for the list of built-in type aliases).
autoMapping If present, MyBatis will enable or disable the automapping for this ResultMap. This attribute overrides the global autoMappingBehavior. Default: unset.

最佳实践 一般逐步创建结果映射。单元测试的真正帮助在这里。若是你尝试建立 一次建立一个向上面示例那样的巨大的结果映射, 那么可能会有错误并且很难去控制它 来工做。开始简单一些,一步一步的发展。并且要进行单元测试!使用该框架的缺点是 它们有时是黑盒(是否可见源代码) 。你肯定你实现想要的行为的最好选择是编写单元 测试。它也能够你帮助获得提交时的错误。

下面一部分将详细说明每一个元素。

 

id & result

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

  

这些是结果映射最基本内容。id 和 result 都映射一个单独列的值到简单数据类型(字符 串,整型,双精度浮点数,日期等)的单独属性或字段。

这二者之间的惟一不一样是 id 表示的结果将是当比较对象实例时用到的标识属性。这帮 助来改进总体表现,特别是缓存和嵌入结果映射(也就是联合映射) 。

每一个都有一些属性:

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 咱们在前面讨论过默认的类型处理器。使用这个属性,你能够覆盖默 认的类型处理器。这个属性值是类的彻底限定名或者是一个类型处理 器的实现,或者是类型别名。

支持的 JDBC 类型

为了将来的参考,MyBatis 经过包含的 jdbcType 枚举型,支持下面的 JDBC 类型。

BIT FLOAT CHAR TIMESTAMP OTHER UNDEFINED
TINYINT REAL VARCHAR BINARY BLOG NVARCHAR
SMALLINT DOUBLE LONGVARCHAR VARBINARY CLOB NCHAR
INTEGER NUMERIC DATE LONGVARBINARY BOOLEAN NCLOB
BIGINT DECIMAL TIME NULL CURSOR ARRAY

构造方法

<constructor>
   <idArg column="id" javaType="int"/>
   <arg column="username" javaType="String"/>
</constructor>

  

对于大多数数据传输对象(Data Transfer Object,DTO)类型,属性能够起做用,并且像 你绝大多数的领域模型, 指令也许是你想使用一成不变的类的地方。 一般包含引用或查询数 据的表不多或基本不变的话对一成不变的类来讲是合适的。 构造方法注入容许你在初始化时 为类设置属性的值,而不用暴露出公有方法。MyBatis 也支持私有属性和私有 JavaBeans 属 性来达到这个目的,可是一些人更青睐构造方法注入。构造方法元素支持这个。

看看下面这个构造方法:

public class User {
   //...
   public User(int id, String username) {
     //...
  }
//...
}

  为了向这个构造方法中注入结果,MyBatis 须要经过它的参数的类型来标识构造方法。 Java 没有自查(反射)参数名的方法。因此当建立一个构造方法元素时,保证参数是按顺序 排列的,并且数据类型也是肯定的。

<constructor>
   <idArg column="id" javaType="int"/>
   <arg column="username" javaType="String"/>
</constructor>

  

关联

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

  

关联元素处理“有一个”类型的关系。好比,在咱们的示例中,一个博客有一个用户。 关联映射就工做于这种结果之上。你指定了目标属性,来获取值的列,属性的 java 类型(很 多状况下 MyBatis 能够本身算出来) ,若是须要的话还有 jdbc 类型,若是你想覆盖或获取的 结果值还须要类型控制器。

关联中不一样的是你须要告诉 MyBatis 如何加载关联。MyBatis 在这方面会有两种不一样的 方式:

  • 嵌套查询:经过执行另一个 SQL 映射语句来返回预期的复杂类型。
  • 嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集。首先,然让咱们来查看这个元素的属性。全部的你都会看到,它和普通的只由 select 和

resultMap 属性的结果映射不一样。

关联的嵌套查询

属性 描述
column 来自数据库的类名,或重命名的列标签。这和一般传递给 resultSet.getString(columnName)方法的字符串是相同的。 column 注 意 : 要 处 理 复 合 主 键 , 你 可 以 指 定 多 个 列 名 通 过 column= ” {prop1=col1,prop2=col2} ” 这种语法来传递给嵌套查询语 句。这会引发 prop1 和 prop2 以参数对象形式来设置给目标嵌套查询语句。
select 另一个映射语句的 ID,能够加载这个属性映射须要的复杂类型。获取的 在列属性中指定的列的值将被传递给目标 select 语句做为参数。表格后面 有一个详细的示例。 select 注 意 : 要 处 理 复 合 主 键 , 你 可 以 指 定 多 个 列 名 通 过 column= ” {prop1=col1,prop2=col2} ” 这种语法来传递给嵌套查询语 句。这会引发 prop1 和 prop2 以参数对象形式来设置给目标嵌套查询语句。
示例:
 
 
<resultMap id="blogResult" type="Blog">
  <association property="author" column="author_id" javaType="Author" select="selectAuthor"/>
</resultMap>

<select id="selectBlog" parameterType="int" resultMap="blogResult">
  SELECT * FROM BLOG WHERE ID = #{id}
</select>

<select id="selectAuthor" parameterType="int" resultType="Author">
  SELECT * FROM AUTHOR WHERE ID = #{id}
</select>

  

咱们有两个查询语句:一个来加载博客,另一个来加载做者,并且博客的结果映射描 述了“selectAuthor”语句应该被用来加载它的 author 属性。

其余全部的属性将会被自动加载,假设它们的列和属性名相匹配。

这种方式很简单, 可是对于大型数据集合和列表将不会表现很好。 问题就是咱们熟知的 “N+1 查询问题”。归纳地讲,N+1 查询问题能够是这样引发的:

  • 你执行了一个单独的 SQL 语句来获取结果列表(就是“+1”)。
  • 对返回的每条记录,你执行了一个查询语句来为每一个加载细节(就是“N”)。

这个问题会致使成百上千的 SQL 语句被执行。这一般不是指望的。

MyBatis 能延迟加载这样的查询就是一个好处,所以你能够分散这些语句同时运行的消 耗。然而,若是你加载一个列表,以后迅速迭代来访问嵌套的数据,你会调用全部的延迟加 载,这样的行为多是很糟糕的。

因此还有另一种方法。

关联的嵌套结果

属性 描述
resultMap 这是结果映射的 ID,能够映射关联的嵌套结果到一个合适的对象图中。这 是一种替代方法来调用另一个查询语句。这容许你联合多个表来合成到 resultMap 一个单独的结果集。这样的结果集可能包含重复,数据的重复组须要被分 解,合理映射到一个嵌套的对象图。为了使它变得容易,MyBatis 让你“链 接”结果映射,来处理嵌套结果。一个例子会很容易来仿照,这个表格后 面也有一个示例。
columnPrefix When joining multiple tables, you would have to use column alias to avoid duplicated column names in the ResultSet. Specifying columnPrefix allows you to map such columns to an external resultMap. Please see the example explained later in this section.
notNullColumn By default a child object is created only if at least one of the columns mapped to the child's properties is non null. With this attribute you can change this behaviour by specifiying which columns must have a value so MyBatis will create a child object only if any of those columns is not null. Multiple column names can be specified using a comma as a separator. Default value: unset.

在上面你已经看到了一个很是复杂的嵌套关联的示例。 下面这个是一个很是简单的示例 来讲明它如何工做。代替了执行一个分离的语句,咱们联合博客表和做者表在一块儿,就像:

 

<select id="selectBlog" parameterType="int" resultMap="blogResult">
  select
    B.id            as blog_id,
    B.title         as blog_title,
    B.author_id     as blog_author_id,
    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
  from Blog B left outer join Author A on B.author_id = A.id
  where B.id = #{id}
</select>

  注意这个联合查询, 以及采起保护来确保全部结果被惟一并且清晰的名字来重命名。 这使得映射很是简单。如今咱们能够映射这个结果:

<resultMap id="blogResult" type="Blog">
  <id property="id" column="blog_id" />
  <result property="title" column="blog_title"/>
  <association property="author" column="blog_author_id" javaType="Author" resultMap="authorResult"/>
</resultMap>

<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>

  

在上面的示例中你能够看到博客的做者关联表明着“authorResult”结果映射来加载做 者实例。

很是重要: 在嵌套据诶过映射中 id 元素扮演了很是重要的角色。应应该一般指定一个 或多个属性,它们能够用来惟一标识结果。实际上就是若是你离开她了,可是有一个严重的 性能问题时 MyBatis 仍然能够工做。选择的属性越少越好,它们能够惟一地标识结果。主键 就是一个显而易见的选择(尽管是联合主键)。

如今,上面的示例用了外部的结果映射元素来映射关联。这使得 Author 结果映射能够 重用。然而,若是你不须要重用它的话,或者你仅仅引用你全部的结果映射合到一个单独描 述的结果映射中。你能够嵌套结果映射。这里给出使用这种方式的相同示例:

<resultMap id="blogResult" type="Blog">
  <id property="id" column="blog_id" />
  <result property="title" column="blog_title"/>
  <association property="author" javaType="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"/>
  </association>
</resultMap>

  上面你已经看到了如何处理“有一个”类型关联。可是“有不少个”是怎样的?下面这 个部分就是来讨论这个主题的。

集合

<collection property="posts" ofType="domain.blog.Post">
  <id property="id" column="post_id"/>
  <result property="subject" column="post_subject"/>
  <result property="body" column="post_body"/>
</collection>

  

集合元素的做用几乎和关联是相同的。实际上,它们也很类似,文档的异同是多余的。 因此咱们更多关注于它们的不一样。

咱们来继续上面的示例,一个博客只有一个做者。可是博客有不少文章。在博客类中, 这能够由下面这样的写法来表示:

private List<Post> posts;

  

要映射嵌套结果集合到 List 中,咱们使用集合元素。就像关联元素同样,咱们能够从 链接中使用嵌套查询,或者嵌套结果。

集合的嵌套查

首先,让咱们看看使用嵌套查询来为博客加载文章。

<resultMap id="blogResult" type="Blog">
  <collection property="posts" javaType="ArrayList" column="id" ofType="Post" select="selectPostsForBlog"/>
</resultMap>

<select id="selectBlog" parameterType="int" resultMap="blogResult">
  SELECT * FROM BLOG WHERE ID = #{id}
</select>

<select id="selectPostsForBlog" parameterType="int" resultType="Blog">
  SELECT * FROM POST WHERE BLOG_ID = #{id}
</select>

  这里你应该注意不少东西,但大部分代码和上面的关联元素是很是类似的。首先,你应 该注意咱们使用的是集合元素。而后要注意那个新的“ofType”属性。这个属性用来区分 JavaBean(或字段)属性类型和集合包含的类型来讲是很重要的。因此你能够读出下面这个 映射:

<collection property="posts" javaType="ArrayList" column="id" ofType="Post" select="selectPostsForBlog"/>

  

读做: “在 Post 类型的 ArrayList 中的 posts 的集合。”

javaType 属性是不须要的,由于 MyBatis 在不少状况下会为你算出来。因此你能够缩短 写法:

<collection property="posts" column="id" ofType="Post" select="selectPostsForBlog"/>

  

集合的嵌套结果

至此,你能够猜想集合的嵌套结果是如何来工做的,由于它和关联彻底相同,除了它应 用了一个“ofType”属性

First, let's look at the SQL:

<select id="selectBlog" parameterType="int" 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>

  咱们又一次联合了博客表和文章表,并且关注于保证特性,结果列标签的简单映射。现 在用文章映射集合映射博客,能够简单写为:

<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>

  

一样,要记得 id 元素的重要性,若是你不记得了,请阅读上面的关联部分。

一样, 若是你引用更长的形式容许你的结果映射的更多重用, 你可使用下面这个替代 的映射:

<resultMap id="blogResult" type="Blog">
  <id property="id" column="blog_id" />
  <result property="title" column="blog_title"/>
  <collection property="posts" ofType="Post" resultMap="blogPostResult" columnPrefix="post_"/>
</resultMap>

<resultMap id="blogPostResult" type="Post">
  <id property="id" column="id"/>
  <result property="subject" column="subject"/>
  <result property="body" column="body"/>
</resultMap>

  

注意 这个对你所映射的内容没有深度,广度或关联和集合相联合的限制。当映射它们 时你应该在大脑中保留它们的表现。 你的应用在找到最佳方法前要一直进行的单元测试和性 能测试。好在 myBatis 让你后来能够改变想法,而不对你的代码形成很小(或任何)影响。

高级关联和集合映射是一个深度的主题。文档只能给你介绍到这了。加上一点联系,你 会很快清楚它们的用法。

鉴别器

<discriminator javaType="int" column="draft">
  <case value="1" resultType="DraftPost"/>
</discriminator>

  

有时一个单独的数据库查询也许返回不少不一样 (可是但愿有些关联) 数据类型的结果集。 鉴别器元素就是被设计来处理这个状况的, 还有包括类的继承层次结构。 鉴别器很是容易理 解,由于它的表现很像 Java 语言中的 switch 语句。

定义鉴别器指定了 column 和 javaType 属性。 列是 MyBatis 查找比较值的地方。 JavaType 是须要被用来保证等价测试的合适类型(尽管字符串在不少情形下都会有用)。好比:

<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>

  在这个示例中, MyBatis 会从结果集中获得每条记录, 而后比较它的 vehicle 类型的值。 若是它匹配任何一个鉴别器的实例,那么就使用这个实例指定的结果映射。换句话说,这样 作彻底是剩余的结果映射被忽略(除非它被扩展,这在第二个示例中讨论) 。若是没有任何 一个实例相匹配,那么 MyBatis 仅仅使用鉴别器块外定义的结果映射。因此,若是 carResult 按以下声明:

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

  那么只有 doorCount 属性会被加载。这步完成后完整地容许鉴别器实例的独立组,尽管 和父结果映射可能没有什么关系。这种状况下,咱们固然知道 cars 和 vehicles 之间有关系, 如 Car 是一个 Vehicle 实例。所以,咱们想要剩余的属性也被加载。咱们设置的结果映射的 简单改变以下。

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

  

如今 vehicleResult 和 carResult 的属性都会被加载了。

尽管曾经有些人会发现这个外部映射定义会多少有一些使人厌烦之处。 所以还有另一 种语法来作简洁的映射风格。好比:

<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" resultType="carResult">
      <result property="doorCount" column="door_count" />
    </case>
    <case value="2" resultType="truckResult">
      <result property="boxSize" column="box_size" />
      <result property="extendedCab" column="extended_cab" />
    </case>
    <case value="3" resultType="vanResult">
      <result property="powerSlidingDoor" column="power_sliding_door" />
    </case>
    <case value="4" resultType="suvResult">
      <result property="allWheelDrive" column="all_wheel_drive" />
    </case>
  </discriminator>
</resultMap>

  要记得 这些都是结果映射, 若是你不指定任何结果, 那么 MyBatis 将会为你自动匹配列 和属性。因此这些例子中的大部分是很冗长的,而实际上是不须要的。也就是说,不少数据库 是很复杂的,咱们不太可能对全部示例都能依靠它。

相关文章
相关标签/搜索