例子到此結(jié)束,我想這兩種完成方法大部分Java程序員都遇到過。兩種方式都行得通,但是在項(xiàng)目的技術(shù)選型(Spring+Mybatis+Mysql)下面,哪種跟好呢?
我的個人經(jīng)驗(yàn)是如果業(yè)務(wù)邏輯不是太復(fù)雜,兩種無所謂。但是如果業(yè)務(wù)邏輯太復(fù)雜,vo各種嵌套model和vo的話,我非常強(qiáng)烈的推薦第二種。(其實(shí)第二中可能hibernate更加適合,但是在此處不考慮),在筆者的這次需求中,使用第一中方式查詢速度為5s,而改為第二種方式之后查詢速度為60ms。提升的太快了。
PS:上面的數(shù)字僅供參考,沒太多實(shí)際意義,因?yàn)檫@個與具體代碼的編寫有關(guān)。
好了,言歸正傳。我們來說說第二種中的使用的Mybatis的ResultMap的使用。
resultMap 元素是 MyBatis 中最重要最強(qiáng)大的元素。它就是讓你遠(yuǎn)離 90%的需要從結(jié)果 集中取出數(shù)據(jù)的 JDBC 代碼的那個東西, 而且在一些情形下允許你做一些 JDBC 不支持的事 情。 事實(shí)上, 編寫相似于對復(fù)雜語句聯(lián)合映射這些等同的代碼, 也許可以跨過上千行的代碼。 ResultMap 的設(shè)計就是簡單語句不需要明確的結(jié)果映射,而很多復(fù)雜語句確實(shí)需要描述它們 的關(guān)系。
你已經(jīng)看到簡單映射語句的示例了,但沒有明確的 resultMap。比如:
12345 | <select id= "selectUsers" parameterType= "int" resultType= "hashmap" > select id, username, hashedPassWord from some_table where id = #{id} </select> |
這樣一個語句簡單作用于所有列被自動映射到 HashMap 的鍵上,這由 resultType 屬性 指定。這在很多情況下是有用的,但是 HashMap 不能很好描述一個領(lǐng)域模型。那樣你的應(yīng) 用程序?qū)褂?JavaBeans 或 POJOs(Plain Old Java Objects,普通 Java 對象)來作為領(lǐng)域 模型。MyBatis 對兩者都支持。看看下面這個 JavaBean:
12345678910111213141516171819202122232425 | 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 的規(guī)范,上面這個類有 3 個屬性:id,username 和 hashedPassword。這些 在 select 語句中會精確匹配到列名。
這樣的一個 JavaBean 可以被映射到結(jié)果集,就像映射到 HashMap 一樣簡單。
12345 | <select id= "selectUsers" parameterType= "int" resultType= "com.someapp.model.User" > select id, username, hashedPassword from some_table where id = #{id} </select> |
要記住類型別名是你的伙伴。使用它們你可以不用輸入類的全路徑。比如:
123456789 | <!-- In mybatis-config.xml file --> <typeAlias type= "com.someapp.model.User" alias= "User" /> <!-- In SQL Mapping XML file --> <select id= "selectUsers" parameterType= "int" resultType= "User" > select id, username, hashedPassword from some_table where id = #{id} </select> |
這些情況下,MyBatis 會在幕后自動創(chuàng)建一個 ResultMap,基于屬性名來映射列到 JavaBean 的屬性上。如果列名沒有精確匹配,你可以在列名上使用 select 字句的別名(一個 基本的 SQL 特性)來匹配標(biāo)簽。比如:
12345678 | <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 最優(yōu)秀的地方你已經(jīng)了解了很多了,但是你還沒有真正的看到一個。這些簡 單的示例不需要比你看到的更多東西。 只是出于示例的原因, 讓我們來看看最后一個示例中 外部的 resultMap 是什么樣子的,這也是解決列名不匹配的另外一種方式。
12345 | <resultMap id= "userResultMap" type= "User" > <id property= "id" column= "user_id" /> <result property= "username" column= "username" /> <result property= "password" column= "password" /> </resultMap> |
引用它的語句使用 resultMap 屬性就行了(注意我們?nèi)サ袅?resultType 屬性)。比如:
12345 | <select id= "selectUsers" parameterType= "int" resultMap= "userResultMap" > select user_id, user_name, hashed_password from some_table where id = #{id} </select> |
如果世界總是這么簡單就好了。
比如,我們?nèi)绾斡成湎旅孢@個語句?
12345678910111213141516171819202122232425262728293031323334 | <!-- Very Complex Statement --> <select id= "selectBlogDetails" parameterType= "int" resultMap= "detailedBlogResultMap" > select B.id as blog_id, B.title as blog_title, B.author_id as blog_author_id, A.id as author_id, A.username as author_username, A.password as author_password, A.email as author_email, A.bio as author_bio, A.favourite_section as author_favourite_section, P.id as post_id, P.blog_id as post_blog_id, P.author_id as post_author_id, P.created_on as post_created_on, P.section as post_section, P.subject as post_subject, P.draft as draft, P.body as post_body, C.id as comment_id, C.post_id as comment_post_id, C.name as comment_name, C.comment as comment_text, T.id as tag_id, T.name as tag_name from Blog B left outer join Author A on B.author_id = A.id left outer join Post P on B.id = P.blog_id left outer join Comment C on P.id = C.post_id left outer join Post_Tag PT on PT.post_id = P.id left outer join Tag T on PT.tag_id = T.id where B.id = #{id} </select> |
你可能想把它映射到一個智能的對象模型,包含一個作者寫的博客,有很多的博文,每 篇博文有零條或多條的評論和標(biāo)簽。 下面是一個完整的復(fù)雜結(jié)果映射例子 (假設(shè)作者, 博客, 博文, 評論和標(biāo)簽都是類型的別名) 我們來看看, 。 但是不用緊張, 我們會一步一步來說明。 當(dāng)天最初它看起來令人生畏,但實(shí)際上非常簡單。
1234567891011121314151617181920212223242526272829 | <!-- Very Complex Result Map --> <resultMap id= "detailedBlogResultMap" type= "Blog" > <constructor> <idArg column= "blog_id" javaType= "int" /> </constructor> <result property= "title" column= "blog_title" /> <association property= "author" javaType= "Author" > <id property= "id" column= "author_id" /> <result property= "username" column= "author_username" /> <result property= "password" column= "author_password" /> <result property= "email" column= "author_email" /> <result property= "bio" column= "author_bio" /> <result property= "favouriteSection" column= "author_favourite_section" /> </association> <collection property= "posts" ofType= "Post" > <id property= "id" column= "post_id" /> <result property= "subject" column= "post_subject" /> <association property= "author" javaType= "Author" /> <collection property= "comments" ofType= "Comment" > <id property= "id" column= "comment_id" /> </collection> <collection property= "tags" ofType= "Tag" > <id property= "id" column= "tag_id" /> </collection> <discriminator javaType= "int" column= "draft" > < case value= "1" resultType= "DraftPost" /> </discriminator> </collection> </resultMap> |
resultMap 元素有很多子元素和一個值得討論的結(jié)構(gòu)。 下面是 resultMap 元素的概念視圖
Attribute | Description |
---|---|
id | A unique identifier in this namespace that can be used to reference this result map. |
type | A fully qualified Java class name, or a type alias (see the table above for the list of built-in type aliases). |
autoMapping | If present, MyBatis will enable or disable the automapping for this ResultMap. This attribute overrides the global autoMappingBehavior. Default: unset. |
最佳實(shí)踐 通常逐步建立結(jié)果映射。單元測試的真正幫助在這里。如果你嘗試創(chuàng)建 一次創(chuàng)建一個向上面示例那樣的巨大的結(jié)果映射, 那么可能會有錯誤而且很難去控制它 來工作。開始簡單一些,一步一步的發(fā)展。而且要進(jìn)行單元測試!使用該框架的缺點(diǎn)是 它們有時是黑盒(是否可見源代碼) 。你確定你實(shí)現(xiàn)想要的行為的最好選擇是編寫單元 測試。它也可以你幫助得到提交時的錯誤。
下面一部分將詳細(xì)說明每個元素。
12 | <id property= "id" column= "post_id" /> <result property= "subject" column= "post_subject" /> |
這些是結(jié)果映射最基本內(nèi)容。id 和 result 都映射一個單獨(dú)列的值到簡單數(shù)據(jù)類型(字符 串,整型,雙精度浮點(diǎn)數(shù),日期等)的單獨(dú)屬性或字段。
這兩者之間的唯一不同是 id 表示的結(jié)果將是當(dāng)比較對象實(shí)例時用到的標(biāo)識屬性。這幫 助來改進(jìn)整體表現(xiàn),特別是緩存和嵌入結(jié)果映射(也就是聯(lián)合映射) 。
每個都有一些屬性:
屬性 | 描述 |
---|---|
property | 映射到列結(jié)果的字段或?qū)傩浴H绻ヅ涞氖谴嬖诘?和給定名稱相同 的 JavaBeans 的屬性,那么就會使用。否則 MyBatis 將會尋找給定名稱 property 的字段。這兩種情形你可以使用通常點(diǎn)式的復(fù)雜屬性導(dǎo)航。比如,你 可以這樣映射一些東西: “username” ,或者映射到一些復(fù)雜的東西: “address.street.number” 。 |
column | 從數(shù)據(jù)庫中得到的列名,或者是列名的重命名標(biāo)簽。這也是通常和會 傳遞給 resultSet.getString(columnName)方法參數(shù)中相同的字符串。 |
javaType | 一個 Java 類的完全限定名,或一個類型別名(參加上面內(nèi)建類型別名 的列表) 。如果你映射到一個 JavaBean,MyBatis 通常可以斷定類型。 然而,如果你映射到的是 HashMap,那么你應(yīng)該明確地指定 javaType 來保證所需的行為。 |
jdbcType | 在這個表格之后的所支持的 JDBC 類型列表中的類型。JDBC 類型是僅 僅需要對插入,更新和刪除操作可能為空的列進(jìn)行處理。這是 JDBC jdbcType 的需要,而不是 MyBatis 的。如果你直接使用 JDBC 編程,你需要指定 這個類型-但僅僅對可能為空的值。 |
typeHandler | 我們在前面討論過默認(rèn)的類型處理器。使用這個屬性,你可以覆蓋默 認(rèn)的類型處理器。這個屬性值是類的完全限定名或者是一個類型處理 器的實(shí)現(xiàn),或者是類型別名。 |
BIT | FLOAT | CHAR | TIMESTAMP | OTHER | UNDEFINED |
TINYINT | REAL | VARCHAR | BINARY | BLOG | NVARCHAR |
SMALLINT | DOUBLE | LONGVARCHAR | VARBINARY | CLOB | NCHAR |
INTEGER | NUMERIC | DATE | LONGVARBINARY | BOOLEAN | NCLOB |
BIGINT | DECIMAL | TIME | NULL | CURSOR | ARRAY |
1234 | <constructor> <idArg column= "id" javaType= "int" /> <arg column= "username" javaType= "String" /> </constructor> |
對于大多數(shù)數(shù)據(jù)傳輸對象(Data Transfer Object,DTO)類型,屬性可以起作用,而且像 你絕大多數(shù)的領(lǐng)域模型, 指令也許是你想使用一成不變的類的地方。 通常包含引用或查詢數(shù) 據(jù)的表很少或基本不變的話對一成不變的類來說是合適的。 構(gòu)造方法注入允許你在初始化時 為類設(shè)置屬性的值,而不用暴露出公有方法。MyBatis 也支持私有屬性和私有 JavaBeans 屬 性來達(dá)到這個目的,但是一些人更青睞構(gòu)造方法注入。構(gòu)造方法元素支持這個。
看看下面這個構(gòu)造方法:
1234567 | public class User { //... public User( int id, String username) { //... } //... } |
為了向這個構(gòu)造方法中注入結(jié)果,MyBatis 需要通過它的參數(shù)的類型來標(biāo)識構(gòu)造方法。 Java 沒有自查(反射)參數(shù)名的方法。所以當(dāng)創(chuàng)建一個構(gòu)造方法元素時,保證參數(shù)是按順序 排列的,而且數(shù)據(jù)類型也是確定的。
1234 | <constructor> <idArg column= "id" javaType= "int" /> <arg column= "username" javaType= "String" /> </constructor> |
1234 | <association property= "author" column= "blog_author_id" javaType= "Author" > <id property= "id" column= "author_id" /> <result property= "username" column= "author_username" /> </association> |
關(guān)聯(lián)元素處理“有一個”類型的關(guān)系。比如,在我們的示例中,一個博客有一個用戶。 關(guān)聯(lián)映射就工作于這種結(jié)果之上。你指定了目標(biāo)屬性,來獲取值的列,屬性的 java 類型(很 多情況下 MyBatis 可以自己算出來) ,如果需要的話還有 jdbc 類型,如果你想覆蓋或獲取的 結(jié)果值還需要類型控制器。
關(guān)聯(lián)中不同的是你需要告訴 MyBatis 如何加載關(guān)聯(lián)。MyBatis 在這方面會有兩種不同的 方式:
嵌套查詢:通過執(zhí)行另外一個 SQL 映射語句來返回預(yù)期的復(fù)雜類型。嵌套結(jié)果:使用嵌套結(jié)果映射來處理重復(fù)的聯(lián)合結(jié)果的子集。首先,然讓我們來查看這個元素的屬性。所有的你都會看到,它和普通的只由 select 和resultMap 屬性的結(jié)果映射不同。
屬性 | 描述 |
---|---|
column | 來自數(shù)據(jù)庫的類名,或重命名的列標(biāo)簽。這和通常傳遞給 resultSet.getString(columnName)方法的字符串是相同的。 column 注 意 : 要 處 理 復(fù) 合 主 鍵 , 你 可 以 指 定 多 個 列 名 通 過 column= ” {prop1=col1,prop2=col2} ” 這種語法來傳遞給嵌套查詢語 句。這會引起 prop1 和 prop2 以參數(shù)對象形式來設(shè)置給目標(biāo)嵌套查詢語句。 |
select | 另外一個映射語句的 ID,可以加載這個屬性映射需要的復(fù)雜類型。獲取的 在列屬性中指定的列的值將被傳遞給目標(biāo) select 語句作為參數(shù)。表格后面 有一個詳細(xì)的示例。 select 注 意 : 要 處 理 復(fù) 合 主 鍵 , 你 可 以 指 定 多 個 列 名 通 過 column= ” {prop1=col1,prop2=col2} ” 這種語法來傳遞給嵌套查詢語 句。這會引起 prop1 和 prop2 以參數(shù)對象形式來設(shè)置給目標(biāo)嵌套查詢語句。 |
1234567891011 | <resultMap id= "blogResult" type= "Blog" > <association property= "author" column= "author_id" javaType= "Author" select= "selectAuthor" /> </resultMap> <select id= "selectBlog" parameterType= "int" resultMap= "blogResult" > SELECT * FROM BLOG WHERE ID = #{id} </select> <select id= "selectAuthor" parameterType= "int" resultType= "Author" > SELECT * FROM AUTHOR WHERE ID = #{id} </select> |
我們有兩個查詢語句:一個來加載博客,另外一個來加載作者,而且博客的結(jié)果映射描 述了“selectAuthor”語句應(yīng)該被用來加載它的 author 屬性。
其他所有的屬性將會被自動加載,假設(shè)它們的列和屬性名相匹配。
這種方式很簡單, 但是對于大型數(shù)據(jù)集合和列表將不會表現(xiàn)很好。 問題就是我們熟知的 “N+1 查詢問題”。概括地講,N+1 查詢問題可以是這樣引起的:
你執(zhí)行了一個單獨(dú)的 SQL 語句來獲取結(jié)果列表(就是“+1”)。對返回的每條記錄,你執(zhí)行了一個查詢語句來為每個加載細(xì)節(jié)(就是“N”)。這個問題會導(dǎo)致成百上千的 SQL 語句被執(zhí)行。這通常不是期望的。
MyBatis 能延遲加載這樣的查詢就是一個好處,因此你可以分散這些語句同時運(yùn)行的消 耗。然而,如果你加載一個列表,之后迅速迭代來訪問嵌套的數(shù)據(jù),你會調(diào)用所有的延遲加 載,這樣的行為可能是很糟糕的。
所以還有另外一種方法。
屬性 | 描述 |
---|---|
resultMap | 這是結(jié)果映射的 ID,可以映射關(guān)聯(lián)的嵌套結(jié)果到一個合適的對象圖中。這 是一種替代方法來調(diào)用另外一個查詢語句。這允許你聯(lián)合多個表來合成到 resultMap 一個單獨(dú)的結(jié)果集。這樣的結(jié)果集可能包含重復(fù),數(shù)據(jù)的重復(fù)組需要被分 解,合理映射到一個嵌套的對象圖。為了使它變得容易,MyBatis 讓你“鏈 接”結(jié)果映射,來處理嵌套結(jié)果。一個例子會很容易來仿照,這個表格后 面也有一個示例。 |
columnPrefix | When joining multiple tables, you would have to use column alias to avoid duplicated column names in the ResultSet. Specifying columnPrefix allows you to map such columns to an external resultMap. Please see the example explained later in this section. |
notNullColumn | By default a child object is created only if at least one of the columns mapped to the child's properties is non null. With this attribute you can change this behaviour by specifiying which columns must have a value so MyBatis will create a child object only if any of those columns is not null. Multiple column names can be specified using a comma as a separator. Default value: unset. |
在上面你已經(jīng)看到了一個非常復(fù)雜的嵌套關(guān)聯(lián)的示例。 下面這個是一個非常簡單的示例 來說明它如何工作。代替了執(zhí)行一個分離的語句,我們聯(lián)合博客表和作者表在一起,就像:
12345678910111213 | <select id= "selectBlog" parameterType= "int" resultMap= "blogResult" > select B.id as blog_id, B.title as blog_title, B.author_id as blog_author_id, A.id as author_id, A.username as author_username, A.password as author_password, A.email as author_email, A.bio as author_bio from Blog B left outer join Author A on B.author_id = A.id where B.id = #{id} </select> |
注意這個聯(lián)合查詢, 以及采取保護(hù)來確保所有結(jié)果被唯一而且清晰的名字來重命名。 這使得映射非常簡單。現(xiàn)在我們可以映射這個結(jié)果:
12345678910111213 | <resultMap id= "blogResult" type= "Blog" > <id property= "id" column= "blog_id" /> <result property= "title" column= "blog_title" /> <association property= "author" column= "blog_author_id" javaType= "Author" resultMap= "authorResult" /> </resultMap> <resultMap id= "authorResult" type= "Author" > <id property= "id" column= "author_id" /> <result property= "username" column= "author_username" /> <result property= "password" column= "author_password" /> <result property= "email" column= "author_email" /> <result property= "bio" column= "author_bio" /> </resultMap> |
在上面的示例中你可以看到博客的作者關(guān)聯(lián)代表著“authorResult”結(jié)果映射來加載作 者實(shí)例。
非常重要: 在嵌套據(jù)誒過映射中 id 元素扮演了非常重要的角色。應(yīng)應(yīng)該通常指定一個 或多個屬性,它們可以用來唯一標(biāo)識結(jié)果。實(shí)際上就是如果你離開她了,但是有一個嚴(yán)重的 性能問題時 MyBatis 仍然可以工作。選擇的屬性越少越好,它們可以唯一地標(biāo)識結(jié)果。主鍵 就是一個顯而易見的選擇(盡管是聯(lián)合主鍵)。
現(xiàn)在,上面的示例用了外部的結(jié)果映射元素來映射關(guān)聯(lián)。這使得 Author 結(jié)果映射可以 重用。然而,如果你不需要重用它的話,或者你僅僅引用你所有的結(jié)果映射合到一個單獨(dú)描 述的結(jié)果映射中。你可以嵌套結(jié)果映射。這里給出使用這種方式的相同示例:
1234567891011 | <resultMap id= "blogResult" type= "Blog" > <id property= "id" column= "blog_id" /> <result property= "title" column= "blog_title" /> <association property= "author" javaType= "Author" > <id property= "id" column= "author_id" /> <result property= "username" column= "author_username" /> <result property= "password" column= "author_password" /> <result property= "email" column= "author_email" /> <result property= "bio" column= "author_bio" /> </association> </resultMap> |
上面你已經(jīng)看到了如何處理“有一個”類型關(guān)聯(lián)。但是“有很多個”是怎樣的?下面這 個部分就是來討論這個主題的。
12345 | <collection property= "posts" ofType= "domain.blog.Post" > <id property= "id" column= "post_id" /> <result property= "subject" column= "post_subject" /> <result property= "body" column= "post_body" /> </collection> |
集合元素的作用幾乎和關(guān)聯(lián)是相同的。實(shí)際上,它們也很相似,文檔的異同是多余的。 所以我們更多關(guān)注于它們的不同。
我們來繼續(xù)上面的示例,一個博客只有一個作者。但是博客有很多文章。在博客類中, 這可以由下面這樣的寫法來表示:
1 | private List<Post> posts; |
要映射嵌套結(jié)果集合到 List 中,我們使用集合元素。就像關(guān)聯(lián)元素一樣,我們可以從 連接中使用嵌套查詢,或者嵌套結(jié)果。
1234567891011 | <resultMap id= "blogResult" type= "Blog" > <collection property= "posts" javaType= "ArrayList" column= "id" ofType= "Post" select= "selectPostsForBlog" /> </resultMap> <select id= "selectBlog" parameterType= "int" resultMap= "blogResult" > SELECT * FROM BLOG WHERE ID = #{id} </select> <select id= "selectPostsForBlog" parameterType= "int" resultType= "Blog" > SELECT * FROM POST WHERE BLOG_ID = #{id} </select> |
這里你應(yīng)該注意很多東西,但大部分代碼和上面的關(guān)聯(lián)元素是非常相似的。首先,你應(yīng) 該注意我們使用的是集合元素。然后要注意那個新的“ofType”屬性。這個屬性用來區(qū)分 JavaBean(或字段)屬性類型和集合包含的類型來說是很重要的。所以你可以讀出下面這個 映射:
1 | <collection property= "posts" javaType= "ArrayList" column= "id" ofType= "Post" select= "selectPostsForBlog" /> |
讀作: “在 Post 類型的 ArrayList 中的 posts 的集合。”
javaType 屬性是不需要的,因?yàn)?MyBatis 在很多情況下會為你算出來。所以你可以縮短 寫法:
1 | <collection property= "posts" column= "id" ofType= "Post" select= "selectPostsForBlog" /> |
至此,你可以猜測集合的嵌套結(jié)果是如何來工作的,因?yàn)樗完P(guān)聯(lián)完全相同,除了它應(yīng) 用了一個“ofType”屬性
First, let's look at the SQL:
123456789101112 | <select id= "selectBlog" parameterType= "int" resultMap= "blogResult" > select B.id as blog_id, B.title as blog_title, B.author_id as blog_author_id, P.id as post_id, P.subject as post_subject, P.body as post_body, from Blog B left outer join Post P on B.id = P.blog_id where B.id = #{id} </select> |
我們又一次聯(lián)合了博客表和文章表,而且關(guān)注于保證特性,結(jié)果列標(biāo)簽的簡單映射。現(xiàn) 在用文章映射集合映射博客,可以簡單寫為:
123456789 | <resultMap id= "blogResult" type= "Blog" > <id property= "id" column= "blog_id" /> <result property= "title" column= "blog_title" /> <collection property= "posts" ofType= "Post" > <id property= "id" column= "post_id" /> <result property= "subject" column= "post_subject" /> <result property= "body" column= "post_body" /> </collection> </resultMap> |
同樣,要記得 id 元素的重要性,如果你不記得了,請閱讀上面的關(guān)聯(lián)部分。
同樣, 如果你引用更長的形式允許你的結(jié)果映射的更多重用, 你可以使用下面這個替代 的映射:
1234567891011 | <resultMap id= "blogResult" type= "Blog" > <id property= "id" column= "blog_id" /> <result property= "title" column= "blog_title" /> <collection property= "posts" ofType= "Post" resultMap= "blogPostResult" columnPrefix= "post_" /> </resultMap> <resultMap id= "blogPostResult" type= "Post" > <id property= "id" column= "id" /> <result property= "subject" column= "subject" /> <result property= "body" column= "body" /> </resultMap> |
注意 這個對你所映射的內(nèi)容沒有深度,廣度或關(guān)聯(lián)和集合相聯(lián)合的限制。當(dāng)映射它們 時你應(yīng)該在大腦中保留它們的表現(xiàn)。 你的應(yīng)用在找到最佳方法前要一直進(jìn)行的單元測試和性 能測試。好在 myBatis 讓你后來可以改變想法,而不對你的代碼造成很小(或任何)影響。
高級關(guān)聯(lián)和集合映射是一個深度的主題。文檔只能給你介紹到這了。加上一點(diǎn)聯(lián)系,你 會很快清楚它們的用法。
123 | <discriminator javaType= "int" column= "draft" > < case value= "1" resultType= "DraftPost" /> </discriminator> |
有時一個單獨(dú)的數(shù)據(jù)庫查詢也許返回很多不同 (但是希望有些關(guān)聯(lián)) 數(shù)據(jù)類型的結(jié)果集。 鑒別器元素就是被設(shè)計來處理這個情況的, 還有包括類的繼承層次結(jié)構(gòu)。 鑒別器非常容易理 解,因?yàn)樗谋憩F(xiàn)很像 Java 語言中的 switch 語句。
定義鑒別器指定了 column 和 javaType 屬性。 列是 MyBatis 查找比較值的地方。 JavaType 是需要被用來保證等價測試的合適類型(盡管字符串在很多情形下都會有用)。比如:
1234567891011121314 | <resultMap id= "vehicleResult" type= "Vehicle" > <id property= "id" column= "id" /> <result property= "vin" column= "vin" /> <result property= "year" column= "year" /> <result property= "make" column= "make" /> <result property= "model" column= "model" /> <result property= "color" column= "color" /> <discriminator javaType= "int" column= "vehicle_type" > < case value= "1" resultMap= "carResult" /> < case value= "2" resultMap= "truckResult" /> < case value= "3" resultMap= "vanResult" /> < case value= "4" resultMap= "suvResult" /> </discriminator> </resultMap> |
在這個示例中, MyBatis 會從結(jié)果集中得到每條記錄, 然后比較它的 vehicle 類型的值。 如果它匹配任何一個鑒別器的實(shí)例,那么就使用這個實(shí)例指定的結(jié)果映射。換句話說,這樣 做完全是剩余的結(jié)果映射被忽略(除非它被擴(kuò)展,這在第二個示例中討論) 。如果沒有任何 一個實(shí)例相匹配,那么 MyBatis 僅僅使用鑒別器塊外定義的結(jié)果映射。所以,如果 carResult 按如下聲明:
123 | <resultMap id= "carResult" type= "Car" > <result property= "doorCount" column= "door_count" /> </resultMap> |
那么只有 doorCount 屬性會被加載。這步完成后完整地允許鑒別器實(shí)例的獨(dú)立組,盡管 和父結(jié)果映射可能沒有什么關(guān)系。這種情況下,我們當(dāng)然知道 cars 和 vehicles 之間有關(guān)系, 如 Car 是一個 Vehicle 實(shí)例。因此,我們想要剩余的屬性也被加載。我們設(shè)置的結(jié)果映射的 簡單改變?nèi)缦隆?/p>
123 | <resultMap id= "carResult" type= "Car" extends = "vehicleResult" > <result property= "doorCount" column= "door_count" /> </resultMap> |
現(xiàn)在 vehicleResult 和 carResult 的屬性都會被加載了。
盡管曾經(jīng)有些人會發(fā)現(xiàn)這個外部映射定義會多少有一些令人厭煩之處。 因此還有另外一 種語法來做簡潔的映射風(fēng)格。比如:
1234567891011121314151617181920212223 | <resultMap id= "vehicleResult" type= "Vehicle" > <id property= "id" column= "id" /> <result property= "vin" column= "vin" /> <result property= "year" column= "year" /> <result property= "make" column= "make" /> <result property= "model" column= "model" /> <result property= "color" column= "color" /> <discriminator javaType= "int" column= "vehicle_type" > < case value= "1" resultType= "carResult" > <result property= "doorCount" column= "door_count" /> </ case > < case value= "2" resultType= "truckResult" > <result property= "boxSize" column= "box_size" /> <result property= "extendedCab" column= "extended_cab" /> </ case > < case value= "3" resultType= "vanResult" > <result property= "powerSlidingDoor" column= "power_sliding_door" /> </ case > < case value= "4" resultType= "suvResult" > <result property= "allWheelDrive" column= "all_wheel_drive" /> </ case > </discriminator> </resultMap> |
要記得 這些都是結(jié)果映射, 如果你不指定任何結(jié)果, 那么 MyBatis 將會為你自動匹配列 和屬性。所以這些例子中的大部分是很冗長的,而其實(shí)是不需要的。也就是說,很多數(shù)據(jù)庫 是很復(fù)雜的,我們不太可能對所有示例都能依靠它。
新聞熱點(diǎn)
疑難解答
圖片精選