您好,登錄后才能下訂單哦!
resultMap 元素是 MyBatis 中最重要最強大的元素。它就是讓你遠離 90%的需要從結果集中取出數據的 JDBC 代碼的那個東西,而且在一些情形下允許你做一些 JDBC 不支持的事情。事實上,編寫相似于對復雜語句聯合映射這些等同的代碼,也許可以跨過上千行的代碼。
ResultMap 的設計就是簡單語句不需要明確的結果映射,而很多復雜語句確實需要描述它們的關系。
你已經看到簡單映射語句的示例了,但沒有明確的 resultMap。比如:
<select id=”selectUsers” parameterType=”int” resultType=”hashmap”>
select id, username, hashedPassword
from some_table
where id = #{id}
</select>
這樣一個語句簡單作用于所有列被自動映射到 HashMap 的鍵上,這由resultType 屬性指定。這在很多情況下是有用的,但是 HashMap 不能很好描述一個領域模型。那樣你的應用程序將會使用 JavaBeans 或 POJOs來作為領域模型。MyBatis 對兩者都支持。看看下面這個 JavaBean:
package com.someapp.model;
public class User {
private int id;
private String username;
private String hashedPassword;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getHashedPassword() {
return hashedPassword;
}
public void setHashedPassword(String hashedPassword) {
this.hashedPassword = hashedPassword;
}
}
基于 JavaBean 的規范,上面這個類有 3 個屬性:id,username 和hashedPassword。這些在 select 語句中會精確匹配到列名。這樣的一個 JavaBean 可以被映射到結果集,就像映射到 HashMap 一樣簡單。
<select id=”selectUsers” parameterType=”int”
resultType=”com.someapp.model.User”>
select id, username, hashedPassword
from some_table
where id = #{id}
</select>
要記住類型別名是你的伙伴。使用它們你可以不用輸入類的全路徑。比如:
<!-- 在XML配置文件中-->
<typeAlias type=”com.someapp.model.User” alias=”User”/>
<!-- 在SQL映射的XML文件中-->
<select id=”selectUsers” parameterType=”int”
resultType=”User”>
select id, username, hashedPassword
from some_table
where id = #{id}
</select>
這些情況下,MyBatis 會在幕后自動創建一個 ResultMap,基于屬性名來映射列到JavaBean 的屬性上。如果列名沒有精確匹配,你可以在列名上使用 select 字句的別名(一個標準的 SQL 特性)來匹配標簽。比如:
<select id=”selectUsers” parameterType=”int” resultType=”User”>
select
user_id as “id”,
user_name as “userName”,
hashed_password as “hashedPassword”
from some_table
where id = #{id}
</select>
那么如何試用外部的 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” parameterType=”int”
resultMap=”userResultMap”>
select user_id, user_name, hashed_password
from some_table
where id = #{id}
</select>
ReulstMap只是字段與屬性之間的映射關系的集合,那么,真正的字段與屬性之間的映射關系,ResultMapping(org.apache.ibatis.mapping.ResultMapping)屬性映射來描述。
ResultMap數據結構如下:
package org.apache.ibatis.mapping;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import org.apache.ibatis.session.Configuration;
/**
* 結果映射,保存著表與對象之間的映射關系
*
*/
public class ResultMap {
// 對應<resultMap>的id屬性
private String id;
// 對應<resultMap>的type屬性
private Class<?> type;
// 對應除<discriminator>元素外的所有屬性映射關系
private List<ResultMapping> resultMappings;
// 對應所有屬性映射中帶有ID標志的映射關系,包括<id>元素和<constructor>的<idArg>子元素
private List<ResultMapping> idResultMappings;
// 對應所有屬性映射中帶有Constructor標志的映射關系,包括<constructor>所有子元素
private List<ResultMapping> constructorResultMappings;
// 對應所有屬性映射中不帶有Constructor標志的映射關系
private List<ResultMapping> propertyResultMappings;
// 對應所有屬性映射中的column屬性的集合
private Set<String> mappedColumns;
// 鑒別器,對應<discriminator>元素
private Discriminator discriminator;
// 是否含有嵌套的結果映射,
// 如果某個屬性映射存在resultMap屬性,且不存在resultSet屬性,則為true
private boolean hasNestedResultMaps;
// 是否含有嵌套查詢,
// 如果某個屬性映射存在select屬性,則為true
private boolean hasNestedQueries;
// 是否開啟自動映射
private Boolean autoMapping;
}
而且在ResultMap類內部有一個靜態的構造類,如下:
//靜態內部類,建造者模式
public static class Builder {
private ResultMapping resultMapping = new ResultMapping();
public Builder(Configuration configuration, String property, String column, TypeHandler<?> typeHandler) {
this(configuration, property);
resultMapping.column = column;
resultMapping.typeHandler = typeHandler;
}
public Builder(Configuration configuration, String property, String column, Class<?> javaType) {
this(configuration, property);
resultMapping.column = column;
resultMapping.javaType = javaType;
}
public Builder(Configuration configuration, String property) {
resultMapping.configuration = configuration;
resultMapping.property = property;
resultMapping.flags = new ArrayList<ResultFlag>();
resultMapping.composites = new ArrayList<ResultMapping>();
resultMapping.lazy = configuration.isLazyLoadingEnabled();
}
public Builder javaType(Class<?> javaType) {
resultMapping.javaType = javaType;
return this;
}
public Builder jdbcType(JdbcType jdbcType) {
resultMapping.jdbcType = jdbcType;
return this;
}
public Builder nestedResultMapId(String nestedResultMapId) {
resultMapping.nestedResultMapId = nestedResultMapId;
return this;
}
public Builder nestedQueryId(String nestedQueryId) {
resultMapping.nestedQueryId = nestedQueryId;
return this;
}
public Builder resultSet(String resultSet) {
resultMapping.resultSet = resultSet;
return this;
}
public Builder foreignColumn(String foreignColumn) {
resultMapping.foreignColumn = foreignColumn;
return this;
}
public Builder notNullColumns(Set<String> notNullColumns) {
resultMapping.notNullColumns = notNullColumns;
return this;
}
public Builder columnPrefix(String columnPrefix) {
resultMapping.columnPrefix = columnPrefix;
return this;
}
public Builder flags(List<ResultFlag> flags) {
resultMapping.flags = flags;
return this;
}
public Builder typeHandler(TypeHandler<?> typeHandler) {
resultMapping.typeHandler = typeHandler;
return this;
}
public Builder composites(List<ResultMapping> composites) {
resultMapping.composites = composites;
return this;
}
public Builder lazy(boolean lazy) {
resultMapping.lazy = lazy;
return this;
}
public ResultMapping build() {
// lock down collections
resultMapping.flags = Collections.unmodifiableList(resultMapping.flags);
resultMapping.composites = Collections.unmodifiableList(resultMapping.composites);
resolveTypeHandler();
validate();
return resultMapping;
}
//一些驗證邏輯,驗證result map有沒有寫錯
private void validate() {
// Issue #697: cannot define both nestedQueryId and nestedResultMapId
if (resultMapping.nestedQueryId != null && resultMapping.nestedResultMapId != null) {
throw new IllegalStateException("Cannot define both nestedQueryId and nestedResultMapId in property " + resultMapping.property);
}
// Issue #5: there should be no mappings without typehandler
if (resultMapping.nestedQueryId == null && resultMapping.nestedResultMapId == null && resultMapping.typeHandler == null) {
throw new IllegalStateException("No typehandler found for property " + resultMapping.property);
}
// Issue #4 and GH #39: column is optional only in nested resultmaps but not in the rest
if (resultMapping.nestedResultMapId == null && resultMapping.column == null && resultMapping.composites.isEmpty()) {
throw new IllegalStateException("Mapping is missing column attribute for property " + resultMapping.property);
}
if (resultMapping.getResultSet() != null) {
int numColums = 0;
if (resultMapping.column != null) {
numColums = resultMapping.column.split(",").length;
}
int numForeignColumns = 0;
if (resultMapping.foreignColumn != null) {
numForeignColumns = resultMapping.foreignColumn.split(",").length;
}
if (numColums != numForeignColumns) {
throw new IllegalStateException("There should be the same number of columns and foreignColumns in property " + resultMapping.property);
}
}
}
private void resolveTypeHandler() {
if (resultMapping.typeHandler == null && resultMapping.javaType != null) {
Configuration configuration = resultMapping.configuration;
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
resultMapping.typeHandler = typeHandlerRegistry.getTypeHandler(resultMapping.javaType, resultMapping.jdbcType);
}
}
public Builder column(String column) {
resultMapping.column = column;
return this;
}
}
ResultMapping數據結構如下:
package org.apache.ibatis.mapping;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;
/**
* 字段映射 一個ResultMapping實例對應ResultSet中一個字段到javaBean中一個屬性的映射關系
*
* sql元素中,除了<discriminator>子元素以外的其他元素都會生成此類型實例,
* 其中包括:
* <idArg><arg><id><result><association><collection>
*
* 內部包含Builder類,負責數據的整合和校驗,不負責傳入參數的解析
* @author Administrator
*
*/
public class ResultMapping {
// 核心配置對象
private Configuration configuration;
// 屬性名,對應元素的property屬性
private String property;
// 字段名,對應元素的column屬性
private String column;
// 屬性的java類型,對應元素的javaType屬性
private Class<?> javaType;
// 字段的jdbc類型,對應元素的jdbcType屬性
private JdbcType jdbcType;
// 類型處理器,對應元素的typeHandler屬性
private TypeHandler<?> typeHandler;
// 對應元素的resultMap屬性應用名稱空間后的結果
private String nestedResultMapId;
// 對應元素的select屬性應用名稱空間后的結果
private String nestedQueryId;
// 對應元素的notNullColumn屬性拆分后的結果
private Set<String> notNullColumns;
// 對應元素的columnPrefix屬性
private String columnPrefix;
// 處理后的標志,標志共兩個:id和constructor
private List<ResultFlag> flags;
// 對應元素的column屬性拆分后生成的結果,composites.size()>0會時column為null
private List<ResultMapping> composites;
// 對應元素的resultSet屬性
private String resultSet;
// 對應元素的foreignColumn屬性
private String foreignColumn;
// 是否延遲加載,對應元素的fetchType屬性值,lazy則為true否則為false
// 也直接從配置對象中讀取
private boolean lazy;
}
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。