天天看點

2K字詳解:MyBatis中核心要點Select resultType和resultMap

作者:會寫代碼的猴子

MyBatis常用動态标簽大全見上述URL,它們大概分為如下四類:

标簽 作用 使用場景
foreach 循環語句 批量添加或者批量查詢
if 條件判斷語句 單條件分支判斷
choose、when、otherwise 類似 Java 中的 switch、case、default 語句 多條件分支判斷
trim、where、set 輔助标簽 用于處理一些條件查詢

  在MyBatis中有一個ResultMap标簽,它是為了映射select标簽查詢出來的結果集,其主要作用是将實體類中的字段與資料庫表中的字段進行關聯映射。

前言

  Mybatis 中 select 标簽有兩個屬性 resultType 和 resultMap,用于在mapper.xml檔案中配置傳回結果類型,工作中經常使用到它們。那麼在日常開發中,應該如何正确的選擇呢?下面我們對這兩個屬性分别進行講解和示範。

結果類型resultType

  resultType直譯就是結果的類型,可以設定為期望從select 語句中傳回結果的類的全限定名或别名。resultType使用場景如下:

  如果查詢結果隻是傳回一個值,比如傳回String、map或int,那麼可以使用resultType指定簡單類型作為輸出結果。

  我們先了解一個resultType的簡單映射語句示例,它沒有顯式地指定 resultMap。比如:

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

  上述語句隻是簡單地将所有的列映射到 HashMap 的鍵上,這由 resultType 屬性指定。此處對查詢字段用了一個 sql 标簽進行封裝,該sql 片段可複用。

  還有一種情況就是如果資料庫表的字段名和實體bean對象的屬性名一樣。 雖然在大部分情況下都夠用,但是 HashMap 并不是一個很好的領域模型;你的程式更可能會使用 JavaBean 或 POJO(普通老式 Java 對象)作為領域模型,MyBatis 對兩者都提供了支援。看看下面這個 JavaBean:

package com.someapp.model;
public class User {
  private int id;
  private String username;
  private String hashedPassword;

 // omit getter,setter and toString
}
           

  基于 JavaBean 的規範,上面這個類有 3 個屬性:id,username 和 hashedPassword,它們會對應到 select 語句中的列名。這樣的一個 JavaBean 可以被映射到 ResultSet,就像映射到 HashMap 一樣簡單。

<select id="selectUsers" resultType="com.someapp.model.User">
  select 
  <include refid="resultTypeColumn"/>
  from some_table
  where id = #{id}
</select>
           

  類型别名是你的好幫手,關于如何設定類型别名,請移步《Spring Boot MyBatis使用type-aliases-package自定義類别名》。使用别名後就可以不用輸入類的全限定名了。譬如:

<select id="selectUsers" resultType="User">
  select 
  <include refid="resultTypeColumn"/>
  from some_table
  where id = #{id}
</select>
           

  在此情況下,MyBatis 會在幕後自動建立一個 resultMap,再根據屬性名來映射列到 JavaBean 的屬性上。如果列名和屬性名不能比對上,可以在 SELECT 語句中設定列别名(這是一個基本的 SQL 特性)來完成比對。例如:

<sql id="resultTypeColumn">
    user_id             as "id",
    user_name           as "userName",
    hashed_password     as "hashedPassword"
</sql>
<select id="selectUsers" resultType="map">
  select 
  	<include refid="resultTypeColumn"/>
  from some_table
  where id = #{id}
</select>
           

  注意,如果傳回的是集合,那應該設定為集合包含的類型,而不是集合本身的類型。

結果映射resultMap

  resultMap 直譯就是結果映射,該元素是 MyBatis 中最重要最強大的元素。與 resultType 相比,resultMap就要強大許多,它不僅能夠用于簡單查詢,還能用于級聯查詢以及設定緩存,功能可謂是十分的強大。它可以讓你從 90% 的 JDBC ResultSets 資料提取代碼中解放出來,并在一些情形下允許你進行一些 JDBC 不支援的操作。實際上,在為一些比如連接配接的複雜語句編寫映射代碼的時候,一份 resultMap 能夠代替實作同等功能的數千行代碼。ResultMap 的設計思想是,對簡單的語句做到零配置,對于複雜一點的語句,隻需要描述語句之間的關系就行了。溫馨提示:resultType 和 resultMap 之間隻能同時使用一個。

resultMap标簽屬性

  resultMap 标簽的屬性值包括兩個:

id 屬性:唯一辨別,此 id 值用于 select 标簽 resultMap 屬性的引用。

type 屬性:表示該 resultMap 的映射結果類型,可以為類的全限定名或者别名。

  resultMap子标簽包括如下幾個 :

子标簽 功能 備注
id 指定查詢列中的唯一辨別,如果有多個列組成唯一辨別,配置多個id 可以不用
result 用于辨別一些簡單屬性,包括column和property兩個屬性 常用
association 在主表的pojo中嵌套另一個表的pojo 不推薦使用
collection 把查詢到的多條記錄映射到集合對象 不推薦使用

  result标簽的屬性包括兩個:

  1. column:資料庫字段名或别名。
  2. property:實體類中的屬性,和column屬性一一對應。

resultMap使用示例

  下面使用一個簡單的例子,來介紹 resultMap 的使用方法。雖然上一節中的例子不用顯式配置 resultMap,但為了講解,我們來看看如果顯式使用外部的 resultMap 會怎樣;這也是解決列名和bean名不比對的另外一種方式。定義一個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>
           

resultType和resultMap的差別

  下面了解一下MyBatis中資料轉換機制:在進行查詢映射的時候,其實查詢出來的每一個屬性都是放在一個對應的Map裡面,其中鍵是屬性名,值則是其對應的值。當提供的傳回類型屬性是resultType的時候,MyBatis會将Map裡面的鍵值對取出賦給resultType所指定的對象對應的屬性。是以,其實MyBatis的每一個查詢映射的傳回類型都是ResultMap,隻是當我們提供的傳回類型屬性是resultType的時候,MyBatis自動的把對應的值賦給resultType所指定對象的屬性,而當提供的傳回類型是resultMap的時候,因為Map不能很好表示領域模型,我們就需要自己把它轉化為對應的對象,這常常在複雜查詢中很有作用。

  言歸正傳,resultType和resultMap到底有什麼差別呢?

  resultType不需要配置,但是resultMap要配置一下。resultType是直接指定傳回類型的,而使用resultMap時,需要在外部ResultMap标簽中,設定資料庫表的字段名和實體bean對象類的屬性的一一對應關系。設定後,就算資料庫的字段名和實體類的屬性名不一樣也沒有關系,mybatis依然會給映射出來,是以resultMap要更強大一些。

  就像上面說的那樣,如果查詢出來資料庫字段名(包括字段别名)和要封裝的實體bean對象屬性值不相同時,隻能使用resultMap來傳回結果。

  還有一個差別是resultMap可以用在複雜聯合查詢上,而resultType不可以。關于這一點,大家可以去Mybatis官網了解一下,這裡點到為止。

結束語

  至此,大家已經了解了resultType和resultMap的基本用法,在日常業務開發中已經可以遊刃有餘了。如果想更上一層樓,掌握更多關于resultMap的進階用法,請移步Mybatis官網。

  當你遇到這個話題的時候,你通常怎麼了解呢?你碰到過特别精彩、讓人印象深刻的回答嗎?歡迎大家積極留言交流。

繼續閱讀