天天看點

java版雲筆記(八)之關聯映射Mybatis關聯映射

通過資料庫對象之間的關聯關系,反映到到實體對象之間的引用。

加載多個表中的關聯資料,封裝到我們的實體對象中。

當業務對資料庫進行關聯查詢。

關聯元素處理“有一個”類型的關系。比如,在我們的示例中,一個部落格有一個使用者。關聯映射就工作于這種結果之上。你指定了目标屬性,來擷取值的列,屬性的 java 類型(很多情況下 MyBatis 可以自己算出來) ,如果需要的話還有 jdbc 類型,如果你想覆寫或擷取的結果值還需要類型控制器。

關聯中不同的是你需要告訴 MyBatis 如何加載關聯。MyBatis 在這方面會有兩種不同的方式:

嵌套查詢:通過執行另外一個 SQL 映射語句來傳回預期的複雜類型。

嵌套結果:使用嵌套結果映射來處理重複的聯合結果的子集。首先,然讓我們來檢視這個元素的屬性。所有的你都會看到,它和普通的隻由 select 和

resultMap 屬性的結果映射不同。

屬性

描述

property

映射到列結果的字段或屬性。如果比對的是存在的,和給定名稱相同的 property JavaBeans 的屬性, 那麼就會使用。否則 MyBatis 将會尋找給定名稱的字段。這兩種情形你可以使用通常點式的複雜屬性導航。比如,你可以這樣映射一 些 東 西 :“ username ”, 或 者 映 射 到 一 些 複 雜 的 東 西 : “address.street.number” 。

javaType

一個 Java 類的完全限定名,或一個類型别名 。如果你映射到一個 JavaBean,MyBatis 通常可以斷定類型。然而,如 javaType 果你映射到的是 HashMap,那麼你應該明确地指定 javaType來保證所需的行為。

jdbcType

在這個表格之前的所支援的 JDBC 類型清單中的類型。JDBC 類型是僅僅需要對插入, 更新和删除操作可能為空的列進行處理。這是 JDBC 的需要, jdbcType 而不是 MyBatis 的。如果你直接使用 JDBC 程式設計,你需要指定這個類型-但僅僅對可能為空的值。

typeHandler

預設的類型處理器。使用這個屬性,你可以覆寫預設的 typeHandler 類型處理器。這個屬性值是類的完全限定名或者是一個類型處理器的實作, 或者是類型别名。

column

來自資料庫的類名,或重命名的列标簽。這和通常傳遞給 resultSet.getString(columnName)方法的字元串是相同的。 column 注 意 : 要 處 理 複 合 主 鍵 , 你 可 以 指 定 多 個 列 名 通 過 column= ” {prop1=col1,prop2=col2} ” 這種文法來傳遞給嵌套查詢語 句。這會引起 prop1 和 prop2 以參數對象形式來設定給目标嵌套查詢語句。

select

另外一個映射語句的 ID,可以加載這個屬性映射需要的複雜類型。擷取的在列屬性中指定的列的值将被傳遞給目标 select 語句作為參數。表格後面有一個詳細的示例。 select 注 意 : 要 處 理 複 合 主 鍵 , 你 可 以 指 定 多 個 列 名 通 過 column= ” {prop1=col1,prop2=col2} ” 這種文法來傳遞給嵌套查詢語 句。這會引起 prop1 和 prop2 以參數對象形式來設定給目标嵌套查詢語句。

fetchType

可選的。有效值為* lazy和eager*。 如果使用了,它将取代全局配置參數lazyLoadingEnabled。

示例:

  我們有兩個查詢語句:一個來加載部落格,另外一個來加載作者,而且部落格的結果映射描述了“selectAuthor”語句應該被用來加載它的 author 屬性。 其他所有的屬性将會被自動加載,假設它們的列和屬性名相比對。

  這種方式很簡單, 但是對于大型資料集合和清單将不會表現很好。問題就是我們熟知的 “N+1 查詢問題”。概括地講,N+1 查詢問題可以是這樣引起的:

 你執行了一個單獨的 SQL 語句來擷取結果清單(就是“+1”)。 對傳回的每條記錄,你執行了一個查詢語句來為每個加載細節(就是“N”)。 這個問題會導緻成百上千的 SQL 語句被執行。這通常不是期望的。   MyBatis 能延遲加載這樣的查詢就是一個好處,是以你可以分散這些語句同時運作的消耗。然而,如果你加載一個清單,之後迅速疊代來通路嵌套的資料,你會調用所有的延遲加載,這樣的行為可能是很糟糕的。

  是以還有另外一種方法。

resultMap

這是結果映射的 ID,可以映射關聯的嵌套結果到一個合适的對象圖中。這是一種替代方法來調用另外一個查詢語句。這允許你聯合多個表來合成到 resultMap 一個單獨的結果集。這樣的結果集可能包含重複,資料的重複組需要被分解,合理映射到一個嵌套的對象圖。為了使它變得容易,MyBatis 讓你“連結”結果映射,來處理嵌套結果。一個例子會很容易來仿照,這個表格後面也有一個示例。

columnPrefix

當連接配接多表時,你将不得不使用列别名來避免ResultSet中的重複列名。指定columnPrefix允許你映射列名到一個外部的結果集中。 請看後面的例子。

notNullColumn

預設情況下,子對象僅在至少一個列映射到其屬性非空時才建立。 通過對這個屬性指定非空的列将改變預設行為,這樣做之後Mybatis将僅在這些列非空時才建立一個子對象。 可以指定多個列名,使用逗号分隔。預設值:未設定(unset)。

autoMapping

如果使用了,當映射結果到目前屬性時,Mybatis将啟用或者禁用自動映射。 該屬性覆寫全局的自動映射行為。 注意它對外部結果集無影響,是以在select or resultMap屬性中這個是毫無意義的。 預設值:未設定(unset)。

在上面你已經看到了一個非常複雜的嵌套關聯的示例。下面這個是一個非常簡單的示例來說明它如何工作。代替了執行一個分離的語句,我們聯合部落格表和作者表在一起,就像:

  注意這個聯合查詢, 以及采取保護來確定所有結果被唯一而且清晰的名字來重命名。這使得映射非常簡單。現在我們可以映射這個結果:

  非常重要: id元素在嵌套結果映射中扮演着非常重要的角色。你應該總是指定一個或多個可以唯一辨別結果的屬性。實際上如果你不指定它的話, MyBatis仍然可以工作,但是會有嚴重的性能問題。在可以唯一辨別結果的情況下, 盡可能少的選擇屬性。主鍵是一個顯而易見的選擇(即使是複合主鍵)。

  現在,上面的示例用了外部的結果映射元素來映射關聯。這使得 Author 結果映射可以重用。然而,如果你不需要重用它的話,或者你僅僅引用你所有的結果映射合到一個單獨描述的結果映射中。你可以嵌套結果映射。

  這裡給出使用這種方式的相同示例(嵌套結果映射):

如果blog有一個co-author怎麼辦? select語句将看起來這個樣子

因為結果中的列名與resultMap中的列名不同。 你需要指定columnPrefix去重用映射co-author結果的resultMap。

  集合元素的作用幾乎和關聯是相同的。實際上,它們也很相似,文檔的異同是多餘的。是以我們更多關注于它們的不同。

  我們來繼續上面的示例,一個部落格隻有一個作者。但是部落格有很多文章。在部落格類中, 這可以由下面這樣的寫法來表示:

  要映射嵌套結果集合到 List 中,我們使用集合元素。就像關聯元素一樣,我們可以從連接配接中使用嵌套查詢,或者嵌套結果。

  首先,讓我們看看使用嵌套查詢來為部落格加載文章

  這裡你應該注意很多東西,但大部分代碼和上面的關聯元素是非常相似的。首先,你應該注意我們使用的是集合元素。然後要注意那個新的“ofType”屬性。這個屬性用來區分 JavaBean(或字段)屬性類型和集合包含的類型來說是很重要的。是以你可以讀出下面這個映射:

  讀作: “在 Post 類型的 ArrayList 中的 posts 的集合。”

  javaType 屬性是不需要的,因為 MyBatis 在很多情況下會為你算出來。是以你可以縮短寫法:

  至此,你可以猜測集合的嵌套結果是如何來工作的,因為它和關聯完全相同,除了它應用了一個“ofType”屬性

  首先,讓我們看一下SQL:

  我們又一次聯合了部落格表和文章表,而且關注于保證特性,結果列标簽的簡單映射。現在用文章映射集合映射部落格,可以簡單寫為:

  同樣,要記得 id 元素的重要性,如果你不記得了,請閱讀上面的關聯部分。

  同樣, 如果你引用更長的形式允許你的結果映射的更多重用, 你可以使用下面這個替代的映射:

   注意 :這個對你所映射的内容沒有深度,廣度或關聯和集合相聯合的限制。當映射它們時你應該在大腦中保留它們的表現。你的應用在找到最佳方法前要一直進行的單元測試和性能測試。好在 myBatis 讓你後來可以改變想法,而不對你的代碼造成很小(或任何)影響。