MyBatis標籤之Select resultType和resultMap

2022-09-18 21:00:46

摘要:介紹MyBatis 中Select標籤的兩個屬性resultType和resultMap及其區別。

1 MyBatis動態SQL之if 語句
2 MyBatis動態sql之where標籤|轉
3 MyBatis動態SQL之set標籤|轉
4 MyBatis動態SQL之trim元素|轉
5 MyBatis動態sql中foreach標籤的使用
6 MyBatis動態SQL之choose(when、otherwise)語句
7 MyBatis動態SQL之bind標籤|轉
8 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官網

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

Reference