resultMap 是 Mybatis 最強大的元素之一,它可以將查詢到的復雜數據(比如查詢到幾個表中數據)映射到一個結果集當中。如在實際應用中,有一個表為(用戶角色表),通過查詢用戶表信息展示頁面,在(用戶表)中存在用戶角色表 id ,在實際列表頁的展示中,用戶關注的是用戶角色名稱,而不是角色 id。解決此類問題可以通過 resultMap 來映射自定義結果。 使用 resultMap 做自定義結果映射,字段名可以不一致,並且還可以指定要顯示的列,比較靈活,應用也廣泛(推薦使用)。
resultMap 知識點
resultMap 元素用來描述如何將結果集映射到 Java 對象,使用 resultMap 對列表展示所需的必要字段來進行自動映射,特別是當數據庫的字段名和實體類 POJO 中的屬性名不一致的情況下,比如角色名稱,字段名/列名 column 是 roleName,而 User 對象的屬性名則為 userRoleName ,此時就需要做映射。
resultMap 元素的屬性值和子節點
id 屬性:唯一標識,此 id 值用於 select 元素 resultMap 屬性的引用。
type 屬性:表示該 resultMap 的映射結果類型。
result 子節點:用於標識一些簡單屬性,其中 column 屬性表示從數據庫中查詢的字段名或別名, property 屬性則表示查詢出來的字段對應的值賦給實體對象的哪個屬性。
說明:MyBatis 中在對查詢進行 select 映射的時候,返回類型可以用 resultType 也可以用 resultMap ,resultType和 resultMap 有一定關聯和區別,應用場景也不同。
resultType 和 resultMap 區別
resultType:直接表示返回類型,包括基礎數據類型和復雜數據類型。
resultMap 則是對外部 resultMap 定義的引用,對應外部 resultMap 的 id,表示返回結果映射到哪一個 resultMap 上。它的應用場景一般是:數據庫字段信息與對象屬性不一致或者需要做復雜的聯合查詢以便自由控制映射結果。
說明:注意,MyBatis 中使用 resultType 做自動映射,一定要注意:字段名和 POJO 的屬性名必須一致。若不一致,則需要給字段起別名,保證別名與屬性名一致。
resultType 和 resultMap 關聯
在 MyBatis 進行查詢映射的時候,其實查詢出來的每個字段值都放在一個對應的 Map 里面,其中鍵是字段名,值則是其對應的值。當 select 元素提供的返回類型屬性是 resultType 的時候, MyBatis 會將 Map 里面的鍵值對取出賦給 resultType 所指定的對象對應的屬性(即調用對應的對象里的屬性的 setter 方法進行填充)。正因為如此,當使用 resultType 的時候,直接在后台就能接收到其相應的對象屬性值。由此可看出,其實 MyBatis 的每個查詢映射的返回類型都是 resultMap ,只是當我們提供的返回類型屬性是 resultType 的時候, MyBatis 會自動把對應的值賦給 resultType 所指定對象的屬性; 而當我們提供的返回類型是 resultMap 的時候,因為 Map 不能很好地表示領域模型,我們就需要通過進一步的定義把它轉化為對應的實體對象。
當返回類型是 resultMap 時,也是非常有用的,這主要用在進行復雜聯合查詢上,當然在進行簡單查詢時是沒有什么必要的,使用 resultType 足以。
說明:
1、Mybatis 是對返回的結果的每一行做映射的,因此在指定 resultType 或者 resultMap 返回類型時應特別注意是一行的類型而不是所有。
2、MyBatis 中在查詢進行 select 映射的時候,返回類型可以用 resultType,也可以用 resultMap,resultType 是直接表示返回類型的,而 resultMap 則是對外部 resultMap 的引用,在 MyBatis 的 select 元素中,resultType 和 resultMap 本質上是一樣的,都是 Map 數據結構。但需要明確一點: resultType 屬性和 resultMap 屬性絕對不能同時存在,只能二者選 其一使用。
3、在 MyBatis 中,使用 resultMap 能夠進行自動映射匹配的前提是字段名和屬性名需要一致,在默認映射級別(PARTIAL)情況下,若一致,即使沒有做屬性名和字段名的匹配,也可以在后台獲取到未匹配過的屬性值;若不一致,且在 resultMap 里沒有做映射,那么就無法在后台獲取並輸出。
案例解析:根據用戶名和用戶角色 id 查詢出用戶表中用戶信息,要求用戶角色要顯示角色名稱而不是角色 id。
方式 1 :使用 resultType 做自動映射 (了解即可)
注意,MyBatis 中使用 resultType 做自動映射,一定要注意:字段名和 POJO 的屬性名必須一致。若不一致,則需要給字段起別名,保證別名與屬性名一致。
(1)修改實體類 POJO:User.java,增加 userRoleName 屬性,添加對應的 get 和 set 方法。 private String userRoleName; //用戶角色名稱 public String getUserRoleName() { return userRoleName; }
public void setUserRoleName(String userRoleName) { this.userRoleName = userRoleName; } (2)UserMapper.java 接口中編寫查詢用戶列表的 getUserList()方法。 /** * 根據用戶名稱(模糊查詢)和用戶角色查詢用戶列表(要求用戶角色要顯示角色名稱而不是角色 id) * @param userName 用戶名稱 * @param userRole 用戶角色 * @return */ public List<User> getUserList(@Param("uName")String userName,@Param("uRole")int userRole); (3)UserMapper.xml 中,編寫查詢用戶列表的 SQL 語句,對表(mbms_user)和角色表(mbms_role)進行連表查詢,使用 resultType 做自動映射。 <!-- 根據用戶名稱(模糊查詢)和用戶角色查詢用戶列表(要求用戶角色要顯示角色名稱而不是角色 id) --> <select id="getUserList" resultType="user"> SELECT u.*,r.roleName AS userRoleName FROM `smbms_user` u,`smbms_role` r WHERE u.`userRole`=r.`id` AND userRole=#{uRole} AND userName LIKE CONCAT('%',#{uName},'%') </select> 說明:使用 resultType 做自動映射,要求數據庫字段名必須和 POJO 屬性名一致。因此要給數據庫字段取別名,別名為 userRoleName 。 (4)單元測試類 @Test //測試根據用戶名稱(模糊查詢)和用戶角色查詢用戶列表(要求用戶角色要顯示角色名稱而不是角色 id) public void testGetUserList(){ List<User> userList=new ArrayList<User>(); String userName="趙"; int userRole=2; userList=session.getMapper(UserMapper.class).getUserList(userName, userRole); for (User user : userList) { System.out.println(user); } } 說明:此種方法必須給 r.roleName 取別名為 userRoleName 。
方式 2 :使用 resultMap 來自定義映射結果(推薦使用)
通過 resultMap 來自定義映射結果。 使用 resultMap 做自定義結果映射,字段名可以不一致,並且還可以指定要顯示的列,比較靈活,應用也廣泛(推薦使用)
(1)修改實體類 POJO:User.java,增加 userRoleName 屬性,添加對應的 get 和 set 方法。 private String userRoleName; //用戶角色名稱 public String getUserRoleName() { return userRoleName; }
public void setUserRoleName(String userRoleName) { this.userRoleName = userRoleName; } (2)UserMapper.java 接口中編寫查詢用戶列表的 getUserList()方法。 /** * 根據用戶名稱(模糊查詢)和用戶角色查詢用戶列表(要求用戶角色要顯示角色名稱而不是角色 id) * @param userName 用戶名稱 * @param userRole 用戶角色 * @return */ public List<User> getUserList(@Param("uName")String userName,@Param("uRole")int userRole); (3)UserMapper.xml 中,編寫查詢用戶列表的 SQL 語句,對表(mbms_user)和角色表(mbms_role)進行連表查詢,使用 resultMap 做自定義結果映射。 <!-- 根據用戶名稱(模糊查詢)和用戶角色查詢用戶列表(要求用戶角色要顯示角色名稱而不是角色 id) --> <select id="getUserList" resultMap="userList"> SELECT u.*,r.roleName FROM `smbms_user` u,`smbms_role` r WHERE u.`userRole`=r.`id` AND userRole=#{uRole} AND userName LIKE CONCAT('%',#{uName},'%') </select> <resultMap type="user" id="userList"> <result property="id" column="id" /> <result property="userCode" column="userCode" /> <result property="userName" column="userName" /> <result property="phone" column="phone" /> <result property="birthday" column="birthday" /> <result property="gender" column="gender" /> <result property="userRole" column="userRole" /> <result property="userRoleName" column="roleName" /> </resultMap> (4)單元測試類
@Test //測試根據用戶名稱(模糊查詢)和用戶角色查詢用戶列表(要求用戶角色要顯示角色名稱而不是角色 id)
public void testGetUserList(){ List<User> userList=new ArrayList<User>(); String userName="趙"; int userRole=2; userList=session.getMapper(UserMapper.class).getUserList(userName, userRole); for (User user : userList) { System.out.println(user); } }
說明:resultMap 做自定義結果映射,與 MyBatis 的自動映射級別(autoMappingBehavior)有關。
注意點
在 MyBatis 中,使用 resultMap 能夠進行自動映射匹配的前提是字段名和屬性名需要一致,在默認映射級別(PARTIAL)情況下,若一致,即使沒有做屬性名和字段名的匹配,也可以在后台獲取到未匹配過的屬性值;若不一致,且在 resultMap 里沒有做映射,那么久無法在后台獲取並輸出。
MyBatis 的自動映射級別
FULL:自動匹配所有。
PARTIAL(默認):自動匹配所有屬性,有內部嵌套(association,collection)的除外。
NONE:禁止自動匹配。
MyBatis 的自動映射級別,需要在 mybatis-config.xml 的 settings 中設置,代碼如下:
<settings> <!--設置 resultMap 的自動映射級別--> <setting name="autoMappingBehavior" value="PARTIAL" /> </settings>