MyBatis標簽之resultType和resultMap
摘要:Mybatis 中 select 標簽有兩個屬性 resultType 和 resultMap,主要作用是在mapper.xml文件中,配置實體類中的字段與數據庫表中的字段關聯映射。本文介紹它們的使用方法和區別。
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標簽之 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 和 resultMap?下面我們對這兩個標簽分別進行講解和演示。
結果類型resultType
??resultType直譯就是結果的類型,可以設置為期望從select 語句中返回結果集的全限定名或別名。resultType使用場景如下:
??如果查詢結果是一個簡單的數據類型,比如基本數據類型String、map、int或者一個簡簡單單的JavaBean,那么,可以使用resultType指定輸出結果集的數據類型。
??測試用例需要完成的功能如下:在查詢用戶表時,需要將user_id、user_name 和 hashed_password 的值映射到 User 對象的 userId 、 userName 和 hashedPassword 屬性上。我們先學習一個使用resultType返回一個map對象的簡單映射語句示例:
<sql id="resultTypeColumn">
user_id as "id",
user_name as "userName",
hashed_password as "hashedPassword"
</sql>
<select id="selectUser" resultType="map">
select
<include refid="resultTypeColumn"/>
from t_user
where id = #{id}
</select>
??指定 resultType 返回值類型為 HashMap 類型時,HashMap 對應的別名是 “map”。上述查詢語句只是簡單地將所有的列映射到 HashMap 的鍵上,這由 resultType 屬性指定。此select豫劇在查詢字段時用了一個 sql 標簽<sql id="resultTypeColumn">進行封裝,該 sql 片段可被復用。
??返回一個字符串:
<select id="getUserNameById" resultType="string">
SELECT user_name as userName FROM t_user WHERE id = #{id}
</select>
??指定 resultType 返回值類型為 String 類型時,java.lang.String對應的別名是“string”。
??還有一種情況就是返回一個實體類對象,要求數據庫表的字段名和實體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="selectUser" resultType="com.someapp.model.User">
select
<include refid="resultTypeColumn"/>
from t_user
where id = #{id}
</select>
返回一個List:
<select id="selectUsers" resultType="com.someapp.model.User">
select
<include refid="resultTypeColumn"/>
from t_user
where user_name like '%胡楊%'
</select>
??類型別名是你的好幫手,關于如何設置類型別名,請移步《Spring Boot MyBatis使用type-aliases-package自定義類別名》。使用別名后就可以不用輸入類的全限定名了。譬如:
<select id="selectUsers" resultType="User">
select
<include refid="resultTypeColumn"/>
from t_user
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 t_user
where id = #{id}
</select>
??注意,如果返回的是集合,那應該設置為集合包含的類型,而不是集合本身的類型。
結果映射resultMap
??resultMap 直譯就是結果映射,它是 MyBatis 中最復雜最彪悍的元素,用來描述如何從數據庫結果集中加載對象。與 resultType 相比,resultMap標簽強大許多,它不僅能夠用于簡單查詢,還能用于級聯查詢以及設置緩存,功能可謂是十分的豐富。它可以讓你從 90% 的 JDBC ResultSets 數據提取代碼中解放出來,并允許我們在一些場景下執行一些 JDBC 不支持的操作。實際上,在為一些比如多表連接的復雜語句編寫映射代碼的時候,一份 resultMap 能夠代替實現同等功能的數千行代碼。ResultMap 的設計思想是,對簡單的語句做到零配置,對于復雜的語句只需要描述語句之間的關系就行了。溫馨提示,resultType 和 resultMap 不能同時存在,只能使用其中一個。
resultMap標簽屬性
??如果數據庫中表的字段與User類的屬性名稱不一致,我們就可以使用resultMap來返回。resultMap 標簽包括兩個重要屬性:
????id 屬性:唯一標識, 用于表示這個resultMap的唯一性。在使用 select 標簽 resultMap 屬性時,就是通過它引用的。
????type 屬性:表示該 resultMap 的結果集映射類型,可以為類的全限定名或者別名。這時候我們就可以定義一個resultMap,來映射結果集中不一樣的字段。
??resultMap子標簽的全部屬性如下:
| 子標簽 | 功能 | 備注 |
|---|---|---|
| id | 指定查詢列中的唯一標識,如果有多個列組成唯一標識,配置多個id | 可以不用 |
| result | 用于標識一些簡單屬性,包括column和property兩個屬性 | 常用 |
| association | 在主表的pojo中嵌套另一個表的pojo | 不推薦使用 |
| collection | 把查詢到的多條記錄映射到集合對象 | 不推薦使用 |
??其中,result標簽的屬性包括兩個:
- column:數據庫表的列名,是數據庫字段名或者用as定義的別名。
- property:實體類的屬性,和列名一模一樣,以進行一一映射。
resultMap使用示例
??下面使用一個簡單的例子,來介紹 resultMap 的使用方法。雖然上一節中的例子不用顯式配置 resultMap,但為了講解,我們來看看如果顯式使用外部的 resultMap 會怎樣;這也是解決列名和bean名不匹配的另外一種方式。定義一個resultMap:
<resultMap id="userResultMap"(唯一標識) type="User"(映射的數據類型,支持別名)>
<!-- column是數據庫中表的字段名,property是實體類的屬性名 -->
<id property="id"(用于映射主鍵字段) column="user_id" />
<result property="userName" column="userName"/>
<result(用于映射一般字段) property="password" column="hashed_password"/>
</resultMap>
??然后在引用它的語句中設置 resultMap 屬性就行了(注意我們去掉了 resultType 屬性)。比如:
<select id="selectUser" resultMap="userResultMap">
select user_id, user_name as userName, hashed_password
from t_user
where id = #{id}
</select>
查詢結果集的數據類型是List<User>:
<select id="selectAllusers" resultMap="userResultMap">
select * from t_user;
</select>
其中,user_name as userName 的功能是為字段 user_name 設置別名userName,因此,resultMap標簽中column就必須寫作userName,保持列名一致。
??如果一個JavaBean中某些屬性為來自另一張表的list,則可以使用collection標簽,本文不做介紹。
resultType和resultMap的區別
??下面了解一下MyBatis中結果集數據類型轉換機制:在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官網。
??你遇到這個話題的時候,通常怎么理解呢?你碰到過特別精彩、讓人印象深刻的回答嗎?歡迎大家積極留言交流。
??更新于2024年2月4日。
Reference
Buy me a coffee. ?Get red packets.
浙公網安備 33010602011771號