MyBatis之Mapper XML 文件详解(三)-Result Maps

白玉 IT哈哈
resultMap 元素是 MyBatis 中最重要最强大的元素。它就是让你远离 90%的需要从结果 集中取出数据的 JDBC 代码的那个东西, 而且在一些情形下允许你做一些 JDBC 不支持的事 情。 事实上, 编写相似于对复杂语句联合映射这些等同的代码, 也许可以跨过上千行的代码。

ResultMap 的设计就是简单语句不需要明确的结果映射,而很多复杂语句确实需要描述它们 的关系。

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

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

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

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 语句中会精确匹配到列名。

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

<select id="selectUsers" 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" resultType="User">  select id, username, hashedPassword  from some_table  where id = #{id}</select>

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

<select id="selectUsers" 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="user_name"/>  <result property="password" column="hashed_password"/></resultMap>

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

<select id="selectUsers" 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" 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

id:当前命名空间中的一个唯一标识,用于标识一个result map.
type:类的全限定名, 或者一个类型别名 (内置的别名可以参考上面的表格).
autoMapping:如果设置这个属性,MyBatis将会为这个ResultMap开启或者关闭自动映射。这个属性会覆盖全局的属性autoMappingBehavior。默认值为: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:我们在前面讨论过默认的类型处理器。使用这个属性,你可以覆盖默 认的类型处理器。这个属性值是类的完全限定名或者是一个类型处理 器的实现,或者是类型别名。

更多相关文章

  1. pgsql 修改字段类型为json
  2. MyBatis之Mapper XML 文件详解(四)-JDBC 类型和嵌套查询
  3. BigDecima类型数据的处理--Non-terminating decimal expansio
  4. 五分钟学会java中的基础类型封装类
  5. 面试必问:String类型为什么设计成不可变的?
  6. 服务端开发指南与最佳实战 | 数据存储技术 | MySQL(01)数据类型的
  7. 基本类型转 String
  8. Java 为什么需要保留基本数据类型
  9. Java 中关于 String 类型的 10 个问题

随机推荐

  1. 用 Vue 开发自己的 Chrome 扩展[每日前端
  2. 我还在生产玩 JDK7,JDK 15 却要来了!|新特
  3. 这才是GraphQL最详细的解释[每日前端夜话
  4. linux 破解root密码时遇到的问题
  5. SpringBoot热部署加持
  6. WebRTC 的现状和未来:专访 W3C WebRTC Cha
  7. Spring Boot Admin 2.0开箱体验
  8. 从一份配置清单详解Nginx服务器配置
  9. 没想到,这么简单的线程池用法,深藏这么多坑
  10. 用TS+GraphQL查询SpaceX火箭发射数据[每