结果映射

resultMap 元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作。实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份 resultMap 能够代替实现同等功能的数千行代码。ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。

之前你已经见过简单映射语句的示例,它们没有显式指定 resultMap。比如:

  1. <select id="selectUsers" resultType="map">
  2. select id, username, hashedPassword
  3. from some_table
  4. where id = #{id}
  5. </select>

上述语句只是简单地将所有的列映射到 HashMap 的键上,这由 resultType 属性指定。虽然在大部分情况下都够用,但是 HashMap 并不是一个很好的领域模型。你的程序更可能会使用 JavaBean 或 POJO(Plain Old Java Objects,普通老式 Java 对象)作为领域模型。MyBatis 对两者都提供了支持。看看下面这个 JavaBean:

  1. package com.someapp.model;
  2. public class User {
  3. private int id;
  4. private String username;
  5. private String hashedPassword;
  6. public int getId() {
  7. return id;
  8. }
  9. public void setId(int id) {
  10. this.id = id;
  11. }
  12. public String getUsername() {
  13. return username;
  14. }
  15. public void setUsername(String username) {
  16. this.username = username;
  17. }
  18. public String getHashedPassword() {
  19. return hashedPassword;
  20. }
  21. public void setHashedPassword(String hashedPassword) {
  22. this.hashedPassword = hashedPassword;
  23. }
  24. }

基于 JavaBean 的规范,上面这个类有 3 个属性:id,username 和 hashedPassword。这些属性会对应到 select 语句中的列名。

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

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

类型别名是你的好帮手。使用它们,你就可以不用输入类的全限定名了。比如:

  1. <!-- mybatis-config.xml 中 -->
  2. <typeAlias type="com.someapp.model.User" alias="User"/>
  3. <!-- SQL 映射 XML 中 -->
  4. <select id="selectUsers" resultType="User">
  5. select id, username, hashedPassword
  6. from some_table
  7. where id = #{id}
  8. </select>

在这些情况下,MyBatis 会在幕后自动创建一个 ResultMap,再根据属性名来映射列到 JavaBean 的属性上。如果列名和属性名不能匹配上,可以在 SELECT 语句中设置列别名(这是一个基本的 SQL 特性)来完成匹配。比如:

  1. <select id="selectUsers" resultType="User">
  2. select
  3. user_id as "id",
  4. user_name as "userName",
  5. hashed_password as "hashedPassword"
  6. from some_table
  7. where id = #{id}
  8. </select>

在学习了上面的知识后,你会发现上面的例子没有一个需要显式配置 ResultMap,这就是 ResultMap 的优秀之处——你完全可以不用显式地配置它们。 虽然上面的例子不用显式配置 ResultMap。 但为了讲解,我们来看看如果在刚刚的示例中,显式使用外部的 resultMap 会怎样,这也是解决列名不匹配的另外一种方式。

  1. <resultMap id="userResultMap" type="User">
  2. <id property="id" column="user_id" />
  3. <result property="username" column="user_name"/>
  4. <result property="password" column="hashed_password"/>
  5. </resultMap>

然后在引用它的语句中设置 resultMap 属性就行了(注意我们去掉了 resultType 属性)。比如:

  1. <select id="selectUsers" resultMap="userResultMap">
  2. select user_id, user_name, hashed_password
  3. from some_table
  4. where id = #{id}
  5. </select>

如果这个世界总是这么简单就好了。