10.關聯關系查詢
關聯關系查詢
當查詢內容涉及到具有關聯關系的多個表時,就需要使用關聯查詢
根據表與表間的關聯關系的不同,關聯查詢分為四種:
(1)一對一關聯查詢
(2)一對多關聯查詢
(3)多對一關聯查詢
(4)多對多關聯查詢
由於日常工作中最常見的關聯關系是一對多、多對一與多對多,所以這裏就不專門只講
解一對一關聯查詢了,其解決方案與多對一解決方案是相同的。
1.一對多關聯查詢
在查詢一方的時候,同時將其所關聯的多方對象也都查詢出來
A、多表連接查詢方式(一條SQL語句):
1 <mapper namespace="com.mybatis.dao.CountryDAO" > 2 <!--parameterType 可以省略 --> 3 4 <resultMap type="Country" id="countryMapper"> 5 <!-- 和解決字段名和屬性名不相同的問題 不同,在這裏,就算屬性名和數據庫中的字段名一致,也要寫出來,不會主動幫你填入的 --> 6 <id column="cid" property="cid"/> 7 <result column="cname" property="cname"/> 8 <!--一對多,一的一方存儲了多的一方,以集合的形式,collection標簽可以幫助我們完成 集合裏面對象的構成 --> 9 <collection property="ministers" ofType="Minister"> 10 <id column="mid" property="mid"/> 11 <result column="mname" property="mname" /> 12 </collection> 13 </resultMap> 14 1516 <!-- 多表連接查詢方式,這種方式 無法進行延遲加載,多的一方直接跟著 一的一方一起查出來了,會消耗很多資源 --> 17 <select id="selectCountryById" resultMap="countryMapper"> 18 <!-- 查詢出了這四個字段,但是這四個字段是無法直接構成country對象的 ,故使用resultMap,讓其將mid,mname構成ministers,再構成country--> 19 select cid,cname,mid,mname from country,minister where countryId = cid and cid = #{cid} 20 </select> 22 </mapper>
在映射文件中使用 <collection/>標簽體現出兩個實體對象間的關聯關系。其兩個屬性的意義位:
property:指定關聯類型,即Country類中的集合類型
ofType:集合屬性的泛型類型
B、多表單獨查詢方式(多條SQL語句)
多表連接查詢方式是將多張表進行連接,連為一張表後進行查詢。其查詢的本質是一張表。
而多表單獨查詢方式是多張表各自查詢各自的相關內容,需要多張表的聯合數據了,
則 將主表的查詢結果聯合其它表的查詢結果,封裝為一個對象。
當然,這多個查詢是可以跨越多個映射文件的,即是可以跨越多個 namespace 的。
在 使用其它 namespace 的查詢時,添加上其所在的 namespace 即可
1 <mapper namespace="com.mybatis.dao.CountryDAO" > 2 3 <resultMap type="Country" id="countryMapper"> 4 <id column="cid" property="cid"/> 5 <result column="cname" property="cname"/> 6 <!-- 執行到這裏時,會調用 select 屬性中的 SQL,column 作為外鍵參數,cid--> 7 <collection property="ministers" ofType="Minister" select="selectMinisterByCountry" column="cid"> 8 </collection> 9 </resultMap> 10 11 <!-- 使用多表單獨查詢的方式(使用多條SQL語句) 采用這種方式,可以實現延遲加載--> 12 <!-- 由DAO調用,故先執行 selectCountryById ,執行到collection,這時需要 執行 selectMinisterByCountry --> 13 <select id="selectCountryById" resultMap="countryMapper"> 14 select cid,cname from country where cid = #{cid} 15 </select> 16 <select id="selectMinisterByCountry" resultType="Minister"> 17 select mid,mname from minister where countryId = #{countryId} 18 </select> 19 20 </mapper>
關聯屬性<collection/>的數據來自於另一個查詢<selectMinisterByCountry/>。
而該查詢<selectMinisterByCountry/>的動態參數 countryId=#{ooo}的值來自於查詢<selectCountryById/>的查詢結果字段 cid
2.多對一關聯查詢
在查詢多方對象的時候,同時將其所關聯的一方對象也查 詢出來。
由於在查詢多方對象時也是一個一個查詢,所以多對一關聯查詢,其實就是一對一關聯查詢
即一對一關聯查詢的實現方式與多對一的實現方式是相同的
1 <mapper namespace="com.mybatis.dao.MinisterDAO" > 2 <!-- parameterType 可以省略 --> 3 4 <resultMap type="Minister" id="ministerMapper"> 5 <!-- 和解決字段名和屬性名不相同的問題 不同,在這裏,就算屬性名和數據庫中的字段名一致,也要寫出來,不會主動幫你填入的 --> 6 <id column="mid" property="mid"/> 7 <result column="mname" property="mname"/> 8 9 <!-- 多對一采用的是 association 來完成關聯屬性的構成 --> 10 <association property="country" javaType="Country"> 11 <id column="cid" property="cid"/> 12 <result column="cname" property="cname"/> 13 </association> 14 </resultMap> 15 16 17 <!-- 多表連接查詢方式,這種方式 無法進行延遲加載,多的一方直接跟著 一的一方一起查出來了,會消耗很多資源 --> 18 <select id="selectMinisterById" resultMap="ministerMapper"> 19 select mid,mname,cid,cname from minister,country where mid = #{mid} and countryId = cid 20 </select> 21 22 </mapper>
註意:在映射文件中使用 <association/> 標簽體現出兩個實體對象間的關聯關系
property:指定關聯屬性,即Minister類中的 country屬性
javaType:關聯屬性的類型
多表單獨查詢的方式
1 <mapper namespace="com.mybatis.dao.MinisterDAO" > 2 <!-- parameterType 可以省略 --> 3 4 <resultMap type="Minister" id="ministerMapper"> 5 <!-- 和解決字段名和屬性名不相同的問題 不同,在這裏,就算屬性名和數據庫中的字段名一致,也要寫出來,不會主動幫你填入的 --> 6 <id column="mid" property="mid"/> 7 <result column="mname" property="mname"/> 8 9 <!-- 多對一采用的是 association 來完成關聯屬性的構成 --> 10 <association property="country" javaType="Country" select="selectCountryById" column="countryId"> 11 <id column="cid" property="cid"/> 12 <result column="cname" property="cname"/> 13 </association> 14 </resultMap> 15 16 17 <!-- 使用多表單獨查詢的方式(使用多條SQL語句) 采用這種方式,可以實現延遲加載--> 18 <select id="selectMinisterById" resultMap="ministerMapper"> 19 select mid,mname,countryId from minister where mid = #{mid} 20 </select> 21 22 <select id="selectCountryById" resultType="Country"> 23 select cid,cname from country where cid = #{countryId} 24 </select> 25 26 </mapper>
3.自關聯查詢
所謂自關聯是指,自己即充當一方,又充當多方,是 1:n 或 n:1 的變型
例如,對於新聞欄目 NewsColumn,可以充當一方,即父欄目,也可以充當多方,即子欄目。而反映到 DB 表中,只有一張表,這張表中具有一個外鍵,用於表示該欄目的父欄目。一級欄目沒有父欄 目,所以可以將其外鍵值設為 0,而子欄目則具有外鍵值。
為了便於理解,將自關聯分為兩種情況來講解。一種是當作 1:n 講解,即當前類作為一 方,其包含多方的集合域屬性。一種是當作 n:1 講解,即當前類作為多方,其包含一方的域 屬性。
下面以新聞欄目為例進行講解。由於 Column 是 DBMS 中的關鍵字,為了避免誤解,將 新聞欄目實體類定義為 NewsLabel。
以一對多方式處理:
以一對多方式處理,即一方可以看到多方。該處理方式的引用場景比較多,例如在頁面上點擊父欄目,顯示出其子欄目
A、查詢指定欄目的所有子孫欄目:
1 <mapper namespace="com.mybatis.dao.NewsLabelDAO" > 2 3 <!-- 自關聯查詢 --> 4 5 <resultMap type="NewsLabel" id="newsLabelMapper"> 6 <id property="id" column="id"/> 7 <result property="name" column="name"/> 8 <!-- pid動態參數值 來自上一次查詢的結果的 id 值 --> 9 <collection property="chirldren" ofType="NewsLabel" select="selectChildrenByParentId" column="id"/> 10 11 </resultMap> 12 13 <!-- select 語句的遞歸調用 --> 14 <!-- 過程:1.先查到 3,4是2 的 子元素 15 2.深度優先,從3開始下手,在構造3的chirldren屬性時,需要去查3下面是否有子元素(因為collection中 使用的select 語句是selectChildrenByParentId) 16 這就構成了遞歸,如果3下面有子元素,則再遞歸著去查這個子元素下面是否還要子元素 17 18 --> 19 <select id="selectChildrenByParentId" resultMap="newsLabelMapper"> 20 select id,name from newslabel where pid = #{pid} 21 </select> 22 23 24 </mapper>
B、查詢指定欄目及其所有子孫欄目:
這裏的查詢結果,即要包含指定 id 的當前欄目,還包含其所有輩份的孫子欄目。
即給 出的 id 實際為當前要查詢的欄目的 id。
1 <!-- 自關聯查詢 --> 2 <resultMap type="NewsLabel" id="newsLabelMapper"> 3 <id property="id" column="id"/> 4 <result property="name" column="name"/> 5 <!-- pid動態參數值 來自上一次查詢的結果的 id 值 --> 6 <collection property="chirldren" ofType="NewsLabel" select="selectChildrenByParent" column="id"/> 7 8 </resultMap> 9 10 <!-- 1.先根據查出 查出對應的 NewsLabel --> 11 <select id="selectNewsLabelById" resultMap="newsLabelMapper"> 12 select id,name from newslabel where id = #{id} 13 </select> 14 15 <!-- 2.再根據前一次出的id 作為 pid,查詢這個id 下所有的子元素 --> 16 <select id="selectChildrenByParent" resultMap="newsLabelMapper"> 17 select id,name from newslabel where pid = #{id} 18 </select> 19 20 21 22 23 </mapper>
以多對一方式處理:
以多對一方式處理,即多方可以看到一方
1 <!-- 自關聯查詢 --> 2 3 <resultMap type="NewsLabel" id="newsLabelMapper"> 4 <id property="id" column="id"/> 5 <result property="name" column="name"/> 6 <!-- pid動態參數值 來自上一次查詢的結果的 id 值 --> 7 <association property="parent" javaType="NewsLabel" select="selectParentByParentId" column="pid"/> 8 9 </resultMap> 10 11 <select id="selectParentByParentId" resultMap="newsLabelMapper"> 12 select id,name,pid from newslabel where id = #{pid} 13 </select> 14 15 16 </mapper>
4.多對多關聯查詢
什麽是多對多關聯關系?一個學生可以選多門課程,而一門課程可以由多個學生選。這就是典型的多對多關系關系。
所以,所謂多對多關系,其實是由兩個互反的一對多關系組成。
一般情況下,多對多關系都會通過一個中間表來建立,例如選課表。
多對多關聯關系也是通過映射文件<resultMap/>的<cooection/>體現的
但是,需要註意的是SQL語句中是對三張表的連接查詢
1 <!-- 多對多查詢 --> 2 3 <resultMap type="Student" id="studentMapper"> 4 <id property="sid" column="sid"/> 5 <result property="sname" column="sname"/> 6 <collection property="courses" ofType="Course" > 7 <id property="cid" column="cid"/> 8 <result property="cname" column="cname"/> 9 </collection> 10 11 </resultMap> 12 13 <select id="selectStudentById" resultMap="studentMapper"> 14 select sid,sname,cid,cname from student,course,middle where sid = studentId and cid = courseId and sid = #{sid} 15 </select>
10.關聯關系查詢