關聯嵌套查詢
示例:
<resultMap id="blogResult" type="Blog"> <association property="author" column="author_id" javaType="Author" select="selectAuthor"/> </resultMap> <select id="selectBlog" resultMap="blogResult"> SELECT * FROM BLOG WHERE ID = #{id} </select> <select id="selectAuthor" resultType="Author"> SELECT * FROM AUTHOR WHERE ID = #{id} </select>
我們有兩個查詢語句:一個來加載博客,另外一個來加載作者,而且博客的結果映射描 述了“selectAuthor”語句應該被用來加載它的 author 屬性。
其他所有的屬性將會被自動加載,假設它們的列和屬性名相匹配。
這種方式很簡單, 但是對於大型數據集合和列表將不會表現很好。 問題就是我們熟知的 “N+1 查詢問題”。概括地講,N+1 查詢問題可以是這樣引起的:
- 你執行了一個單獨的 SQL 語句來獲取結果列表(就是“+1”)。
- 對返回的每條記錄,你執行了一個查詢語句來為每個加載細節(就是“N”)。
這個問題會導致成百上千的 SQL 語句被執行。這通常不是期望的。
MyBatis 能延遲加載這樣的查詢就是一個好處,因此你可以分散這些語句同時運行的消 耗。然而,如果你加載一個列表,之后迅速迭代來訪問嵌套的數據,你會調用所有的延遲加 載,這樣的行為可能是很糟糕的。
所以還有另外一種方法。
關聯的嵌套結果
在上面你已經看到了一個非常復雜的嵌套關聯的示例。 下面這個是一個非常簡單的示例 來說明它如何工作。代替了執行一個分離的語句,我們聯合博客表和作者表在一起,就像:
<select id="selectBlog" 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>
注意這個聯合查詢, 以及采取保護來確保所有結果被唯一而且清晰的名字來重命名。 這使得映射非常簡單。現在我們可以映射這個結果:
<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>
在上面的示例中你可以看到博客的作者關聯代表着“authorResult”結果映射來加載作 者實例。
非常重要: id元素在嵌套結果映射中扮演着非 常重要的角色。你應該總是指定一個或多個可以唯一標識結果的屬性。實際上如果你不指定它的話, MyBatis仍然可以工作,但是會有嚴重的性能問題。在可以唯一標識結果的情況下, 盡可能少的選擇屬性。主鍵是一個顯而易見的選擇(即使是復合主鍵)。
現在,上面的示例用了外部的結果映射元素來映射關聯。這使得 Author 結果映射可以 重用。然而,如果你不需要重用它的話,或者你僅僅引用你所有的結果映射合到一個單獨描 述的結果映射中。你可以嵌套結果映射。這里給出使用這種方式的相同示例:
<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>
如果blog有一個co-author怎么辦? select語句將看起來這個樣子:
<select id="selectBlog" resultMap="blogResult"> select B.id as blog_id, B.title as blog_title, 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, CA.id as co_author_id, CA.username as co_author_username, CA.password as co_author_password, CA.email as co_author_email, CA.bio as co_author_bio from Blog B left outer join Author A on B.author_id = A.id left outer join Author CA on B.co_author_id = CA.id where B.id = #{id} </select>
再次調用Author的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>
因為結果中的列名與resultMap中的列名不同。 你需要指定columnPrefix去重用映射co-author結果的resultMap。
<resultMap id="blogResult" type="Blog"> <id property="id" column="blog_id" /> <result property="title" column="blog_title"/> <association property="author" resultMap="authorResult" /> <association property="coAuthor" resultMap="authorResult" columnPrefix="co_" /> </resultMap>
上面你已經看到了如何處理“有一個”類型關聯。但是“有很多個”是怎樣的?下面這 個部分就是來討論這個主題的。
官方鏈接:http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html